////////////////////////////////////////////////////////////////////////////////////////////////
// including libraries /////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////

#include <avr/pgmspace.h> //acces to a constant array in the program memory
#include <stdio.h>
#include <stdlib.h>
#include <avr/eeprom.h>
#include <avr/io.h>
#include "PIXCIR_algorithm.h"
#include "i2c_master.h"
#include <util/delay.h>
#include <avr/interrupt.h>

/////////////////////////////////////////////////////////////////////////////////////////////////
// define constants, variables and type /////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////////////////

unsigned char I2C_SLAVE=0x5C;  //I2C slave address                     

#define BUF_SIZE 296
#define RAW_CTRL_CONFIG 0x88
#define RAW_ADDR 0x8E
#define BUTTON_RAW_ADDR 43
#define ENGINEERING_MODE_REG 61
#define CROSS_Y_REG 139
#define SLAVE_VERSION 64
#define SPECOP 58
#define POWER_MODE 51
#define INT_MODE 52
#define INT_WIDTH 53
#define IDLE_FREQ 54
#define AUTO_IDLE_DELAY 55
#define WATER_MODE 56
#define TUNE_MODE_CONFIG 96
#define TUNE_CTRL 138
#define SIGNAL_X 41

volatile struct
{
	unsigned int buf_idx; // Incremented when we receive data from UART
	unsigned int cmd_idx; // Incremented when we process the data in the main.c
	unsigned int echo_idx; // Incremented when we echo the data in the main.c
	unsigned char buffer[BUF_SIZE];
} uart_rx;

unsigned char terminal_home[]   PROGMEM = "\e[J\e[;H";
unsigned char terminal_line[]   PROGMEM = "\e[K\r\n";
unsigned char terminal_cancel[]	PROGMEM = "\e[K\e[J\r\n";
unsigned char message_error[]   PROGMEM = "Syntax error\r\n";
unsigned char message_version[] PROGMEM = "I2C master for C44. Pixcir 2013. BV7.1\r\n";
unsigned char message_version_noboot[] PROGMEM = "I2C master for C44. Pixcir 2013. V7.1\r\n";
unsigned char engineering_mode[]PROGMEM = "engineering mode\r\n";
unsigned char user_mode[]       PROGMEM = "user mode\r\n";
unsigned char i2c_mode[]        PROGMEM = "i2c mode\r\n";
unsigned char tune_mode[]        PROGMEM = "tune mode\r\n";
unsigned char no_debug_mode[]   PROGMEM = "Not assigned for debug mode\r\n";
unsigned char unexpected_error[]PROGMEM = "unexpected error\r\n";
unsigned char I2C_TIME_OUT[]    PROGMEM = ": I2C_TIME_OUT\r\n";
unsigned char ATTb_locked[]     PROGMEM = "ATTb not toggle\r\n";
unsigned char strength_str[]    PROGMEM = "_strength: ";
unsigned char message_hex[]     PROGMEM = "0x ";
unsigned char message_ver_over[]PROGMEM = "Slave version isn't ASCII string.\r\n";
unsigned char cancel_autocal[]  PROGMEM = "Auto-calibration offsets cancelled\r\n";

unsigned char message_master_version[]PROGMEM = "Master version: ";
unsigned char message_slave_version[] PROGMEM = "Slave version: ";
unsigned char message_match_address[] PROGMEM = "Bootloader information: ";
unsigned char message_read_register[] PROGMEM = "Read register content: ";
unsigned char message_CRC[]           PROGMEM = "The CRC of the application of the slave: ";
unsigned char message_INT_mode[]      PROGMEM = "INT mode register: ";
unsigned char message_INT_width[]     PROGMEM = "INT width register: ";
unsigned char message_power_mode[]    PROGMEM = "Power mode register: ";
unsigned char message_idle_freq[]     PROGMEM = "Idle freq register: ";
unsigned char message_water_mode[]    PROGMEM = "Water mode register: ";
unsigned char message_button_rawdata[]PROGMEM = "The button rawdata: ";
unsigned char message_button[]        PROGMEM = "The button: ";
unsigned char message_report_rate[]   PROGMEM = "The touch report rate: ";
unsigned char message_water_flag[]    PROGMEM = "The water flag = 0x ";
unsigned char message_eeprom_version[]PROGMEM = "The eeprom structure version: 0x";
unsigned char message_touch_finger_number[]  PROGMEM = "The touch finger number: ";
unsigned char message_auto_idle_delay[]    	 PROGMEM = "Auto idle delay register: ";

unsigned char message_tune_mode[]      PROGMEM = "tune mode register: 0x";
unsigned char message_nbx[]    		   PROGMEM = "the number of x electrodes: 0x";
unsigned char message_nby[]            PROGMEM = "the number of y electrodes: 0x";
//unsigned char message_resx[]    	   PROGMEM = "the x resolution : 0x";
//unsigned char message_resy[]         PROGMEM = "the y resolution : 0x";
unsigned char message_n_fingers[]      PROGMEM = "the report number of fingers : 0x";
unsigned char message_i2c_addr[]       PROGMEM = "the address = 0x ";
unsigned char message_i2c_data[]       PROGMEM = "the data    = 0x ";

//const unsigned char mydata[] __attribute((section(".mydatasection"))) = "20110622-TangoC";

position_t1 pos1;

unsigned int hex=0;
unsigned char ATTb_line=0;
unsigned int hex_counter=0;
unsigned char stop_loop=0;
unsigned char rst_pol = 1;			// RST high active (Renesas way)
unsigned char I2C_WRITE;
unsigned char I2C_READ;
unsigned char ATTb_en=0;
unsigned char nb_XN=0;
unsigned char nb_YN=0;
unsigned int RAW_CTRL_register;
unsigned int TUNE_CTRL_register;
unsigned char i2c_time_out_period=50;//50*4.096ms -> 200ms;
unsigned char master_mode;
unsigned char first_run=1;			//initialize that variable to 0 when the MCU is reseted or powered on
unsigned char raster_frozen;
unsigned char algo_enabled;
unsigned char i2c_time_out_enable=1;
unsigned char repeated_start=1;
unsigned char ver_format=0; 
unsigned int timer0_counter=0;
unsigned int flag_counter=0;
unsigned int attb_pulse=0;
unsigned char bootloader[4] = {0};
unsigned char download_counter=0;
unsigned char turn_8b=0;

unsigned char nbr_res=0;
unsigned int tune_mode_register=0;
unsigned char Master_sync =0;		//bending data = 0, normal rawdata = 1
unsigned char spi_speed_ME1_x = 0;
unsigned char spi_speed_ME1_y = 0;
unsigned char spi_speed_ME0_x = 0;
unsigned char spi_speed_ME0_y = 0;
unsigned int ATTB_counter_max = 65535;
unsigned char EEPROM_version = 0;
unsigned char user_mode_flag = 0;	//user_mode_flag 	=0 INT mode
									//					=1 INT width
									//					=2 Power mode
									//					=3 idle_freq
									//					=4 auto_idle_delay
									//					=5 water mode

extern void PIXCIR_tx232 (unsigned char);
extern void write_INT_mode(char data);

/////////////////////////////////////////////////////////////////////////////////////////////////
// define the RAW control register //////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////////////////

// RAW_CTRL bits definition
#define ONE_UINT16				((unsigned int) 1)
#define CHOOSE_0 				(ONE_UINT16 << 0)	// Choose function (bit0)
#define CHOOSE_1 				(ONE_UINT16 << 1)	// Choose function (bit1) (0: history buffer, 1: RAW data, 2: system info)
#define METHOD 					(ONE_UINT16 << 2)	// Method 0 or 1
#define OFFSET_LOWPASS 			(ONE_UINT16 << 3)	// Enable the offset correction and the low-pass filter
#define SENSITIVITY				(ONE_UINT16 << 4)	// Show ME0 sensitivity adjustment (OFFSET must also be set)
#define M1_PATTERN 				(ONE_UINT16 << 5)	// ME1 pattern (0:pat4, 1:pat8)
#define M1_ROTATION 			(ONE_UINT16 << 6)	// ME1 sense direction (0:Y, 1:X)
#define M1_BAND 				(ONE_UINT16 << 7)	// ME1 band scan (0:single cross node, 1:full X axis scan reported in RAW table)
#define NO_ALGO					(ONE_UINT16 << 8)	// Disable the algo
#define SINGLE_SHOT 			(ONE_UINT16 << 9)	// Enable single shot RAW refresh
#define FREEZE					(ONE_UINT16 << 10)	// RAW refresh freezed after single shot is done	
#define DRIFT_COMP       		(ONE_UINT16 << 11)	// Enable drift comp (For raw data measures)" 
#define RAWDATA_S00       		(ONE_UINT16 << 12)	// Raw data display selection 0
#define RAWDATA_S11       		(ONE_UINT16 << 13)	// Raw data display selection 1
#define RAWDATA_S22       		(ONE_UINT16 << 14)	// Raw data display selection 2
#define RAWDATA_S33       		(ONE_UINT16 << 15)	// Raw data display selection 3

/////////////////////////////////////////////////////////////////////////////////////////////////
// define the TUNE control register /////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////////////////

// TUNE_CTRL bits definition
#define RAWDATA_S0       		(ONE_UINT16 << 0)	// Raw data display selection 0
#define RAWDATA_S1       		(ONE_UINT16 << 1)	// Raw data display selection 1
#define RAWDATA_S2       		(ONE_UINT16 << 2)	// Raw data display selection 2
#define RAWDATA_S3       		(ONE_UINT16 << 3)	// Raw data display selection 3

/////////////////////////////////////////////////////////////////////////////////////////////////
// define the tune mode register ////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////////////////

// tune mode bits definition
#define ONE_UINT16				((unsigned int) 1)
#define TUNING  				(ONE_UINT16 << 0)	// Standard tuning is possible
#define QUALIFY 				(ONE_UINT16 << 1)	// Qualification mode with automatic scan and output for the M1 noise qualification
#define DISPLAY					(ONE_UINT16 << 2)	// Variable data displays can be selected
#define ALGO		 			(ONE_UINT16 << 3)	// Start algorithm see two finger drawing

/////////////////////////////////////////////////////////////////////////////////////////////////
// define a status register for the flags ///////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////////////////

#define reserve_1 15
#define reserve_2 14
#define reserve_3 13
#define reserve_4 12
#define reserve_5 11
#define reserve_6 10
#define reserve_7 9
#define reserve_8 8
#define tune_debug_mode 7
#define report_rate_mode 6
#define button_flag_mode 5
#define strength 4
#define button_mode 3
#define debug_mode 2
#define normal_mode 1
#define no_mode 0

//							+----------------- reserve_1
//							|+---------------- reserve_2
//							||+--------------- reserve_3
//							|||+-------------- reserve_4	
//							||||+------------- reserve_5
//							|||||+------------ reserve_6
//	    					||||||+----------- reserve_7
//							|||||||+---------- reserve_8
//	    					||||||||+--------- tune_debug_mode
//        					|||||||||+-------- report_rate_mode
//        					||||||||||+------- button_flag_mode
//        					|||||||||||+------ strength 
//        					||||||||||||+----- button_mode
//        					|||||||||||||+---- debug_mode
//       					||||||||||||||+--- normal_mode
//        					|||||||||||||||+-- no_mode
//        					||||||||||||||||
unsigned int status_reg = 0b0000000000000000;


/////////////////////////////////////////////////////////////////////////////////////////////////
// Initialize MCU pins and interruptions ////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////////////////

void PIXCIR_initialize_mcu (void) __attribute__ ((naked,section (".init3")));

void PIXCIR_initialize_mcu (void)
{
	asm ("cli");

	/******************************/
	/* Clear MCU Control Register */
	/******************************/
	
	//		  +--------- -
	//        |+-------- BODS: BOD Sleep
	//        ||+------- BODSE: BOD Sleep Enable
	//        |||+------ PUD: Pull-up Disable
	//        ||||+----- -
	//        |||||+---- -
	//        ||||||+--- IVSEL: Interrupt Vector Select
	//        |||||||+-- IVCE: Interrupt Vector Change Enable
	//        ||||||||
	MCUCR = 0b00000000;     // MCU Control Register 
	
	/*************************************/
	/* Clear Sleep Mode Control Register */
	/*************************************/

	//		  +--------- -
	//        |+-------- -
	//        ||+------- -
	//        |||+------ -
	//        ||||+----- SM2  Sleep Mode Select Bit2
	//        |||||+---- SM1  Sleep Mode Select Bit1
	//        ||||||+--- SM0  Sleep Mode Select Bit1
	//        |||||||+-- SE   Sleep Enable
	//        ||||||||
	SMCR =  0b00000000;		// Sleep Mode Control Register , 010 => Power-down mode	
	
	/***********************************/
	/* Enable and lauch Watchdog Timer */
	/***********************************/
	
	//	      +--------- WDIF	watchdog interrupt flag
	//        |+-------- WDIE	interrupt enable instead of reset
	//        ||+------- WDP3	time-out prescaler 3
	//        |||+------ WDCE	watchdog change enable
	//        ||||+----- WDE	watchdog enable
	//        |||||+---- WDP2	time-out prescaler 2
	//        ||||||+--- WDP1	time-out prescaler 1
	//        |||||||+-- WDP0	time-out prescaler 0
	//        ||||||||
	WDTCSR =0b00000000;		// Watchdog is in interrupt/auto-reset mode and running
	
	/**********************************/
	/* Enable external INT0 Interrupt */
	/* Interrupt on falling edge      */
	/**********************************/

	//	      +--------- -
	//        |+-------- -
	//        ||+------- -
	//        |||+------ -
	//        ||||+----- ISC11  Interrupt Sense Control 1 Bit 1
	//        |||||+---- ISC10  Interrupt Sense Control 1 Bit 0	
	//        ||||||+--- ISC01  Interrupt Sense Control 0 Bit 1
	//        |||||||+-- ISC00  Interrupt Sense Control 0 Bit 0
	//        ||||||||
	EICRA = 0b00001000;		// External Interrupt Control Register A , 10 => falling edge			// period = ~18ms (~50Hz)				

	//		  +--------- -
	//        |+-------- -
	//        ||+------- -
	//        |||+------ -
	//        ||||+----- - 
	//        |||||+---- -
	//        ||||||+--- INT1  External Interrupt Request 1 Enable
	//        |||||||+-- INT0  External Interrupt Request 0 Enable
	//        ||||||||
	EIMSK = 0b00000010;     // External Interrupt Mask Register , 1 => Enable INTx

	//		  +--------- -
	//        |+-------- -
	//        ||+------- -
	//        |||+------ -
	//        ||||+----- -
	//        |||||+---- -
	//        ||||||+--- INTF1   External Interrupt Flag 1
	//        |||||||+-- INTF0   External Interrupt Flag 0
	//        ||||||||
	EIFR  = 0b00000000;		// External Interrupt Flag Register

    /******************************/
	/* Disable all Pin Interrupts */
	/******************************/

	//		  +--------- -
	//        |+-------- -
	//        ||+------- -
	//        |||+------ -
	//        ||||+----- -
	//        |||||+---- PCIE2  Pin Change interrupt Enable 2
	//        ||||||+--- PCIE1  Pin Change interrupt Enable 1
	//        |||||||+-- PCIE0  Pin Change interrupt Enable 0
	//        ||||||||
	PCICR =0b00000000;     // Disable Pin Change interrupt

	//		  +--------- PCINT23
	//        |+-------- PCINT22
	//        ||+------- PCINT21
	//        |||+------ PCINT20
	//        ||||+----- PCINT19
	//        |||||+---- PCINT18
	//        ||||||+--- PCINT17
	//        |||||||+-- PCINT16
	//        ||||||||
	PCMSK2 =0b00000000;    // Disable Pin Change interrupt 2

	//		  +--------- -
	//        |+-------- PCINT14
	//        ||+------- PCINT13
	//        |||+------ PCINT12
	//        ||||+----- PCINT11
	//        |||||+---- PCINT10
	//        ||||||+--- PCINT9
	//        |||||||+-- PCINT8
	//        ||||||||
	PCMSK1 =0b00000000;    // Disable Pin Change interrupt 1

	//		  +--------- PCINT7
	//        |+-------- PCINT6
	//        ||+------- PCINT5
	//        |||+------ PCINT4
	//        ||||+----- PCINT3
	//        |||||+---- PCINT2
	//        ||||||+--- PCINT1
	//        |||||||+-- PCINT0
	//        ||||||||
	PCMSK0 =0b00000000;    // Disable Pin Change interrupt 0

    /*****************************/
    /* Config all Pin directions */
	/*****************************/

	//		  +--------- PB7  XTAL2
	//        |+-------- PB6  XTAL1
	//        ||+------- PB5  SPI_CLK
	//        |||+------ PB4  SPI_M2T1
	//        ||||+----- PB3  SPI_T2M1
	//        |||||+---- PB2  CSB1
	//        ||||||+--- PB1  ATTb (pulled high externally by lower resistance value is better regarding cross-talk rejection)
	//        |||||||+-- PB0  CSB1
	//        ||||||||
	PORTB = 0b11111111;	   // Pull-up all pins before changing the direction
	DDRB   =0b00110101;    // Input = 0
	PORTB  =0b00000010;    // Inputs are pulled up if 1   	
	
	//		  +--------- -  
	//        |+-------- PC6  Connected to the Reset pin of ATmega168
	//        ||+------- PC5  SCL (pulled high externally)
	//        |||+------ PC4  SDA (pulled high externally)
	//        ||||+----- PC3  SPI_CLK
	//        |||||+---- PC2  Unused
	//        ||||||+--- PC1  Unused
	//        |||||||+-- PC0  Unused  The simplest method to ensure a defined level of an unused pin, is to enable the internal pull-up.
	//        ||||||||
	PORTC = 0b01111111;	   // Pull-up all pins before changing the direction
	DDRC   =0b00101000;    // Input = 0
	PORTC  =0b01110111;    // Inputs are pulled up if 1

	//		  +--------- PD7  CSB2
	//        |+-------- PD6  SPI_M2T2
	//        ||+------- PD5  SPI_T2M2
	//        |||+------ PD4  Unsed
	//        ||||+----- PD3  SERIAL RX (UART)
	//        |||||+---- PD2  SERIAL TXD (UART)
	//        ||||||+--- PD1  -
	//        |||||||+-- PD0  Connected to the Reset pin of the Slave
	//        ||||||||
	PORTD = 0b11111111;	   // Pull-up all pins before changing the direction
	DDRD   =0b11000101;    // Input = 0
	PORTD  =0b11111111;    // Inputs are pulled up if 1

	/*******************/
	/* TWI programming */
	/*******************/

	//		   +--------- TWINT  TWI Interrupt Flag
	//         |+-------- TWEA   TWI Enable Acknowledge Bit
	//         ||+------- TWSTA  TWI START Condition Bit 
	//         |||+------ TWSTO  TWI STOP Condition Bit
	//         ||||+----- TWWC   TWI Write Collision Flag
	//         |||||+---- TWEN   TWI Enable Bit
	//         ||||||+--- -
	//         |||||||+-- TWIE   TWI Interrupt Enable
	//         ||||||||
	TWCR  =  0b00000000;   // TWI Control Register
    
	//		   +--------- TWBR7  
	//         |+-------- TWBR6   
	//         ||+------- TWBR5  
	//         |||+------ TWBR4  
	//         ||||+----- TWBR3  
	//         |||||+---- TWBR2   
	//         ||||||+--- TWBR1
	//         |||||||+-- TWBR0   
	//         ||||||||	   //TWI Bit Rate Register
	TWBR  =  0b00001100;   //16MHz: 0x20 = 200KHz, 0x0C = 400kHz, 0x5 = 615.4KHz, 0x4 = 666.7KHz, 0x2 = 800KHz
						   //8MHz : 0x2A = 80KHz,  0x20 = 100KHz, 0x5 = 307.8KHz, 0x2 = 400KHz

	//		   +--------- TWSR7  
	//         |+-------- TWSR6   
	//         ||+------- TWSR5  
	//         |||+------ TWSR4  
	//         ||||+----- TWSR3  
	//         |||||+---- -
	//         ||||||+--- TWPS1
	//         |||||||+-- TWPS0   
	//         ||||||||	   //TWI Status Register
	TWSR  =  0b00000000;   

	//		   +--------- TWINT  TWI Interrupt Flag
	//         |+-------- TWEA   TWI Enable Acknowledge Bit
	//         ||+------- TWSTA  TWI START Condition Bit 
	//         |||+------ TWSTO  TWI STOP Condition Bit
	//         ||||+----- TWWC   TWI Write Collision Flag
	//         |||||+---- TWEN   TWI Enable Bit
	//         ||||||+--- -
	//         |||||||+-- TWIE   TWI Interrupt Enable
	//         ||||||||
	TWCR  =  0b00000100;   // TWI Control Register

	/*************************/
	/*******timer0************/
	/**************************/
	
	//		   +--------- COM0A1
	//         |+-------- COM0A0
	//         ||+------- COM0B1
	//         |||+------ COM0B0
	//         ||||+-----
	//         |||||+---- 
	//         ||||||+--- WGM01
	//         |||||||+-- WGM00
	//         ||||||||
	TCCR0A = 0b00000000;

	
	//		   +--------- FOCC0A
	//         |+-------- FOC0B
	//         ||+------- 
	//         |||+------ 
	//         ||||+----- WGM02
	//         |||||+---- CS02    
	//         ||||||+--- CS01   
	//         |||||||+-- CS00   
	//         ||||||||            
	TCCR0B = 0b00000000;	// no clock source

	
	TCNT0 = 0xAF;			//init counter =  175, the timer 0 interrupt period = (255-175)*1us = 80us    

	//		   +---------
	//         |+--------
	//         ||+-------  
	//         |||+------
	//         ||||+----- 
	//         |||||+---- OCIE0B
	//         ||||||+--- OCIE0A
	//         |||||||+-- TOIE0     
	//         ||||||||
	TIMSK0 = 0b00000001;	//enable timer/counter0 overflow interrupt 

	//		  +--------- 
	//        |+-------- 
	//        ||+-------  
	//        |||+------ 
	//        ||||+-----
	//        |||||+---- OCF0B
	//        ||||||+--- OCF0A
	//        |||||||+-- TOV0   
	//        ||||||||
	TIFR0 = 0b00000000;		//timer/counter0 overflow flag

}


/////////////////////////////////////////////////////////////////////////////////////////////////
// Process and convert data types ///////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////////////////

// SEND ON UART A STRING CONSTANT STORED IN PROGRAM SPACE
void PIXCIR_tx232_string (unsigned char *s)
{
	while (pgm_read_byte(s))
	{
		PIXCIR_tx232 (pgm_read_byte(s));
		s++;
	}
}      

// BINARY TO SIGNED DECIMAL ASCII 
void PIXCIR_tx232_int_base10_g (int x, unsigned char skip)
{
	#define BUFSIZE 6
    unsigned char s[BUFSIZE];
    unsigned char i;
	unsigned char neg=0;
	int		rem;
    div_t r;
	
	if (skip)
	{

	    if (x<0)
		{
		    s[0]='-';
		    x=-x;
		}	
	    else
			s[0]='+';

	    for (i=0; i<BUFSIZE-1; i++)
		{
		    r = div (x,10);
		    s[BUFSIZE-1-i] = (unsigned char) (r.rem) + '0';
		    x = r.quot;
		}

	    PIXCIR_tx232 (s[0]);

	    for (unsigned char i=skip; i<BUFSIZE; i++)
			PIXCIR_tx232 (s[i]);

	    PIXCIR_tx232 (' ');
	}
	else
	{
		if (x == 0)
		{
			PIXCIR_tx232('0');
		} 
		else 
		{
			skip = 0;
			if(x < 0) 
			{
				neg = 1; 
				x = -x; 
			}
			while(x)
			{
				rem = x % 10;
				s[skip++] = (char)(rem) + '0';
				x = x / 10;
			}
		
			if (neg == 1) 
				PIXCIR_tx232('-');

			while(skip--) 
				PIXCIR_tx232(s[skip]);
		}
	}
}

void PIXCIR_tx232_int_base10_4 (int x)
{
	PIXCIR_tx232_int_base10_g (x,3);
}

void PIXCIR_tx232_int_base10 (int x)
{
	PIXCIR_tx232_int_base10_g (x,1);
}

char hex_lookup [16] PROGMEM = { '0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'};

void tx_hex (unsigned char x)
{
	PIXCIR_tx232 (pgm_read_byte (hex_lookup + (x >> 4)));
	PIXCIR_tx232 (pgm_read_byte (hex_lookup + (x & 0xF)));
	PIXCIR_tx232 (' ');
}

void tx_hex_comma (unsigned char x)
{
	PIXCIR_tx232 (pgm_read_byte (hex_lookup + (x >> 4)));
	PIXCIR_tx232 (pgm_read_byte (hex_lookup + (x & 0xF)));
	PIXCIR_tx232 (',');
}

unsigned char hex2int (char c)
{
	if (c < 'A')
		return c-'0';
	else 
		return c-'A'+10;
}

char int2hex (unsigned char i)
{
	if (i<10)
		return '0'+i;
	else
		return 'A'+i-10;
}


/////////////////////////////////////////////////////////////////////////////////////////////////
// Timer1 interruption management ////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////////////////

ISR(TIMER1_COMPA_vect)
{
	PIXCIR_tx232_string (terminal_cancel);
	PIXCIR_tx232_string (I2C_TIME_OUT);
	TIMSK1 = 0;
	TCCR1B = 0;

	asm ("JMP 0");	
}

/////////////////////////////////////////////////////////////////////////////////////////////////
// Timer0 interruption management ////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////////////////

ISR(TIMER0_OVF_vect)
{
	TCNT0=0xAF;			//set TCNT0 = 175, the timer 0 interrupt period = (255-175)*1us = 80us           
	timer0_counter++;	
}

/////////////////////////////////////////////////////////////////////////////////////////////////
// I2C mode /////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////////////////

void I2C_mode_read(void)
{
	i2c_start ();
	i2c_write (I2C_READ);
	PIXCIR_tx232_string (message_read_register);

	for (unsigned int i=0; i<(hex); i++)
	{
		tx_hex ((unsigned char) (i2c_read (1)));
	}

	tx_hex ((unsigned char) (i2c_read (0)));
    PIXCIR_tx232('\r');
	PIXCIR_tx232('\n');
	i2c_stop ();
}
/////////////////////////////////////////////////////////////////////////////////////////////////
// RST //////////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////////////////

void rst_pulse(void)
{
	PORTD ^= (1<<PD0); // Toggle RST 

	_delay_ms(20);

	PORTD ^= (1<<PD0);// Toggle RST	
}
void rst_polarity(void)
{
	rst_pol ^= 1;	// Switch polarity

	if (rst_pol)
	{
		PORTD &= ~(1<<PD0);	// Pull RST low (when not active)
	}
	else
		PORTD |= (1<<PD0); // Pull RST high	(when not active)
}
/////////////////////////////////////////////////////////////////////////////////////////////////
// write/read tune ctrl register ////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////////////////
void write_tune_ctrl_reg (void)
{
	i2c_start ();
	i2c_write (I2C_WRITE);
	i2c_write (TUNE_CTRL);
	i2c_write (TUNE_CTRL_register & 0xFF);
	i2c_stop();
}
/////////////////////////////////////////////////////////////////////////////////////////////////
// write/read raw ctrl register /////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////////////////
void write_INT(char data)
{
	i2c_start ();
    i2c_write (I2C_WRITE);
    i2c_write (INT_MODE);
	i2c_write (data&0xFF);
	i2c_stop();
}

void write_raw_ctrl_reg (void)
{
	char INT_reg;
	unsigned int ATTb_counter = 0;

	//store the INT_mode_register
	i2c_start ();
	i2c_write (I2C_WRITE);
	i2c_write (INT_MODE);
	if(!repeated_start)
		i2c_stop();
	i2c_start ();
	i2c_write (I2C_READ);
	INT_reg = i2c_read(0);
	i2c_stop();

	//enable INT interrupt
    write_INT(0x08);

	raster_frozen=0;
	i2c_start ();
	i2c_write (I2C_WRITE);
	i2c_write (RAW_CTRL_CONFIG);
	i2c_write (RAW_CTRL_register & 0xFF);
	i2c_write ((RAW_CTRL_register>>8) & 0xFF);
	i2c_stop();

	while(!(PINB & _BV(PB1)))	//attb line is low

	ATTb_counter = 0;
	while(PINB & _BV(PB1))		//attb line is high
		{
			ATTb_counter++;
			if(ATTb_counter>=ATTB_counter_max)
			break;
		}

	while(!(PINB & _BV(PB1)))	//attb line is low


	ATTb_counter = 0;
	while(PINB & _BV(PB1))		//attb line is high
		{
			ATTb_counter++;
			if(ATTb_counter>=ATTB_counter_max)
			break;
		}

	//recover the INT_mode_register
	write_INT(INT_reg);
}

void PIXCIR_plot_raw_ctrl_register(void)
{
	unsigned char raw_ctrl_low;
	unsigned char raw_ctrl_high;
	int i;
	
	i2c_start ();
	i2c_write (I2C_WRITE);
	i2c_write (RAW_CTRL_CONFIG);
	if(!repeated_start)
		i2c_stop();
	i2c_start ();
	i2c_write (I2C_READ);
	raw_ctrl_low = i2c_read(1);
	raw_ctrl_high = i2c_read(0);
	i2c_stop ();

	PIXCIR_tx232_string (terminal_cancel);
	PIXCIR_tx232('H');
	PIXCIR_tx232(':');

	for (i=0; i<8; i++)
	{
		if (raw_ctrl_high & (1<<(7-i)))
			PIXCIR_tx232('1');
		else
			PIXCIR_tx232('0');
	}

	PIXCIR_tx232(' ');
	PIXCIR_tx232('L');
	PIXCIR_tx232(':');

	for (i=0; i<8; i++)
	{
		if (raw_ctrl_low & (1<<(7-i)))

			PIXCIR_tx232('1');
		else
			PIXCIR_tx232('0');
	}
		
	PIXCIR_tx232_string (terminal_line);
}

/////////////////////////////////////////////////////////////////////////////////////////////////
// enable/diasble offset cancelation and low pass filter flag ///////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////////////////

void calibrated (void)
{
	RAW_CTRL_register |= OFFSET_LOWPASS;
	write_raw_ctrl_reg();
}

void not_calibrated (void)
{
	RAW_CTRL_register &= ~OFFSET_LOWPASS;
	write_raw_ctrl_reg();
}

/////////////////////////////////////////////////////////////////////////////////////////////////
// enable/disable sensitivity ///////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////////////////

void set_sensitivity(void)
{
	RAW_CTRL_register |= OFFSET_LOWPASS|SENSITIVITY;
	write_raw_ctrl_reg();
}

void unset_sensitivity(void)
{
	RAW_CTRL_register &= ~(OFFSET_LOWPASS|SENSITIVITY);
	write_raw_ctrl_reg();
}

/////////////////////////////////////////////////////////////////////////////////////////////////
// set pattern for method 1 /////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////////////////

void set_pat_small (void)
{
	RAW_CTRL_register &= ~M1_PATTERN;
	write_raw_ctrl_reg();		
}

void set_pat_large (void)
{
	RAW_CTRL_register |= M1_PATTERN;
	write_raw_ctrl_reg();		
}

/////////////////////////////////////////////////////////////////////////////////////////////////
// set sens direction for method 1 //////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////////////////

void set_M1_Y (void)
{
	RAW_CTRL_register &= ~M1_ROTATION;
	write_raw_ctrl_reg();		
}

void set_M1_X (void)
{
	RAW_CTRL_register |= M1_ROTATION;
	write_raw_ctrl_reg();		
}

/////////////////////////////////////////////////////////////////////////////////////////////////
// enable/diasble algorithm /////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////////////////

void enable_algo (void)
{
	algo_enabled=1;
	RAW_CTRL_register &= ~NO_ALGO;
	write_raw_ctrl_reg();
}

void disable_algo (void)
{
	algo_enabled=0;
	RAW_CTRL_register |= NO_ALGO;
	write_raw_ctrl_reg();
}

/////////////////////////////////////////////////////////////////////////////////////////////////
// enable/disable drift comp (For raw data measures)/////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////////////////

void enable_comp (void)
{
	RAW_CTRL_register |= DRIFT_COMP;
	write_raw_ctrl_reg();		
}

void disable_comp (void)
{
	RAW_CTRL_register &= ~DRIFT_COMP;
	write_raw_ctrl_reg();		
}

/////////////////////////////////////////////////////////////////////////////////////////////////
// diasble FREEZE ///////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////////////////

void disable_freeze (void)
{
	RAW_CTRL_register &= ~FREEZE;
	write_raw_ctrl_reg();
}

/////////////////////////////////////////////////////////////////////////////////////////////////
// single shot //////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////////////////

void single_shot (void)
{
	RAW_CTRL_register |= SINGLE_SHOT;
	RAW_CTRL_register &= ~(FREEZE);
	write_raw_ctrl_reg();
	RAW_CTRL_register &= ~(SINGLE_SHOT);
	raster_frozen = 1;
}

/////////////////////////////////////////////////////////////////////////////////////////////////
// set/unset bit in RAW_CTRL_register ///////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////////////////

void RAW_CTRL_set_bit (void)
{
	RAW_CTRL_register |= (ONE_UINT16 << (hex & 0x0F));
	write_raw_ctrl_reg();
}

void RAW_CTRL_unset_bit (void)
{
	RAW_CTRL_register &= ~(ONE_UINT16 << (hex & 0x0F));
	write_raw_ctrl_reg();
}

/////////////////////////////////////////////////////////////////////////////////////////////////
// set cross X and cross Y for a single cross measure in M1 /////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////////////////

void set_crossX_crossY (void)
{
	//write cross_X and cross_Y value
	i2c_start ();
	i2c_write (I2C_WRITE);
	i2c_write (138);
	i2c_write ((hex>>8)*0xFF);
	i2c_write (hex*0xFF);
	i2c_stop ();
}

/////////////////////////////////////////////////////////////////////////////////////////////////
// enter master bootloader  /////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////////////////
void enter_master_bootloader(void)
{
  if(pgm_read_byte ((unsigned char*) (0x3ffe)) == 0x5A)
  {
	  eeprom_write_byte ((unsigned char*) 509,0x5A);
	  asm ("jmp 0x3800");
  }
}
/////////////////////////////////////////////////////////////////////////////////////////////////
// Process the outputs for postions /////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////////////////

void position_output (void)
{
	PIXCIR_tx232 ('(');
	PIXCIR_tx232 (' ');

	unsigned char *p = &pos1.touching,n2;
	int n1;

	// flags
	n2 = (*p & 0xF8)>>3;

	// #of fingers
	PIXCIR_tx232_int_base10_g ((*(p++) & 0x07),0);
	PIXCIR_tx232 (',');
	
	// do not disply botoms
	p++;

	// finger display loop
	for (unsigned char i=0; i<5; i++)
	{
		
		// display ID
		PIXCIR_tx232_int_base10_g (*(p+4),0);
		PIXCIR_tx232 (',');

		// display position
		// X
		n1 = (*(p+1)<<8)+(*(p));
		PIXCIR_tx232_int_base10_g (n1,0);
		PIXCIR_tx232 (',');
		// Y
		n1 = (*(p+3)<<8)+(*(p+2));
		PIXCIR_tx232_int_base10_g (n1,0);
		if (i != 4)
			PIXCIR_tx232 (',');

		// next finger
		p+=5;	
	}
	
	flag_counter++;
	if(flag_counter == 50)
	{
		PIXCIR_tx232 (',');
		PIXCIR_tx232 ('F');
		tx_hex (n2);
		PIXCIR_tx232_string (terminal_line);
		flag_counter = 0;
	}
	else
	{
		PIXCIR_tx232_string (terminal_line);
	}
}

void send_position (void)
{
    i2c_start ();
	i2c_write (I2C_WRITE); //write data from master 2 slave
    i2c_write (0);		
	if(!repeated_start)
		i2c_stop();
	i2c_start ();
	i2c_write (I2C_READ);
    
	for (unsigned char i=0; i<31; i++)
	{	
		*((unsigned char*) (&pos1) + i) = i2c_read (1);
	}

	*((unsigned char*) (&pos1)+31) = i2c_read (0);
	i2c_stop ();

	position_output ();
}

/////////////////////////////////////////////////////////////////////////////////////////////////
// Process the outputs for raw data /////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////////////////

void read_raw_data (void)
{
	int i;
	int j;

	if ((RAW_CTRL_register & (METHOD | CHOOSE_1 | CHOOSE_0))==(CHOOSE_0)) //Method 0 raw data
	{
		int rx;
 
		i2c_start ();
		i2c_write (I2C_WRITE);
		i2c_write (RAW_ADDR);
		if(!repeated_start)
			i2c_stop();
		i2c_start ();
		i2c_write (I2C_READ);
		
		PIXCIR_tx232('X');
		for (i=0; i<(nb_XN-1); i++)
		{
			rx = i2c_read(1);
			rx = rx+(((unsigned int)i2c_read(1))<<8);
			PIXCIR_tx232_int_base10_g (rx,0);
			if(i!=nb_XN-2)
				PIXCIR_tx232 (',');		
		}

		PIXCIR_tx232_string (terminal_line);

		PIXCIR_tx232('Y');
		for (i=0; i<(nb_YN-2); i++)
		{
			rx = i2c_read(1);
			rx = rx+(((unsigned int)i2c_read(1))<<8);
			PIXCIR_tx232_int_base10_g (rx,0);
			PIXCIR_tx232 (',');	
		}

		rx = i2c_read(1);
		rx = rx+(((unsigned int)i2c_read(0))<<8);
		i2c_stop();

		PIXCIR_tx232_int_base10_g (rx,0);
		PIXCIR_tx232_string (terminal_line);
		PIXCIR_tx232_string (terminal_home);
	}
	else if((RAW_CTRL_register & (M1_BAND | METHOD | CHOOSE_1 | CHOOSE_0))==(M1_BAND | METHOD | CHOOSE_0)) //Method 1 raster
	{
		unsigned int ATTb_counter = 0;
									
		for (j=0; j<=nb_YN; j++)
		{
			int rx;	

			//write cross_Y value
			i2c_start ();
			i2c_write (I2C_WRITE);
			i2c_write (CROSS_Y_REG);
			i2c_write ((char)j);
			i2c_stop ();
			
			if (!raster_frozen)	// Synchronize on ATTb if not freezed after single shot
			{
				while (PINB & _BV(PB1)) //attb line is high
				{
					_delay_us(6);
					ATTb_counter++;

					if (ATTb_counter >= ATTB_counter_max)
					{
						PIXCIR_tx232_string (ATTb_locked);
						ATTb_counter=0;
						break;
					}
				}
				while (!(PINB & _BV(PB1))) //attb line is low
				{
					_delay_us(6);
					ATTb_counter++;

					if (ATTb_counter >= ATTB_counter_max)
					{
						PIXCIR_tx232_string (ATTb_locked);
						ATTb_counter=0;
						break;
					}
				}

				while (PINB & _BV(PB1)) //attb line is high
				{
					_delay_us(6);
					ATTb_counter++;

					if (ATTb_counter >= ATTB_counter_max)
					{
						PIXCIR_tx232_string (ATTb_locked);
						ATTb_counter=0;
						break;
					}
				}
				while (!(PINB & _BV(PB1))) //attb line is low
				{
					_delay_us(6);
					ATTb_counter++;

					if (ATTb_counter >= ATTB_counter_max)
					{
						PIXCIR_tx232_string (ATTb_locked);
						ATTb_counter=0;
						break;
					}
				}
				_delay_ms(4);
			}
			
			i2c_start ();
			i2c_write (I2C_WRITE);
			i2c_write (RAW_ADDR);
			if(!repeated_start) 
				i2c_stop();
			i2c_start ();
			i2c_write (I2C_READ);

			if (j == 0){PIXCIR_tx232('S');}
			else {PIXCIR_tx232('R');};

			for (i=0; i<nb_XN; i++)				
			{
				rx=i2c_read(1);
				rx = rx+(((unsigned int)i2c_read(1))<<8);
				PIXCIR_tx232_int_base10_g (rx,0);
				PIXCIR_tx232 (',');		
			}

			rx=i2c_read(1);
			rx = rx+(((unsigned int)i2c_read(0))<<8);
			i2c_stop();

			PIXCIR_tx232_int_base10_g (rx,0);
			PIXCIR_tx232 (',');	
			PIXCIR_tx232_string (terminal_line);
		}
	}
	else if((RAW_CTRL_register & (M1_BAND | METHOD | CHOOSE_1 | CHOOSE_0))==(METHOD | CHOOSE_0)) //Method 1 raster for 1 cross node only
	{
		int rx;
		i2c_start ();
		i2c_write (I2C_WRITE);
		i2c_write (140);
		if(!repeated_start)
			i2c_stop();
		i2c_start ();
		i2c_write (I2C_READ);
		rx=i2c_read(1);
		rx = rx+(((unsigned int)i2c_read(0))<<8);
		i2c_stop();

		PIXCIR_tx232_int_base10_g (rx,0);
		PIXCIR_tx232_string (terminal_line);

	}
	else if ((RAW_CTRL_register & (CHOOSE_1 | CHOOSE_0))==(CHOOSE_1)) //system info data
	{
		_delay_ms(200);		
		i2c_start ();
		i2c_write (I2C_WRITE);
		i2c_write (RAW_ADDR);
		if(!repeated_start)
			i2c_stop();
		i2c_start ();
		i2c_write (I2C_READ);
		
		if(EEPROM_version)		//eeprom structure version, 1byte
		{
			i2c_read (1);
			i2c_read (1);
			PIXCIR_tx232_string (message_eeprom_version);
			tx_hex ((unsigned char) (i2c_read (0)));
			EEPROM_version = 0;
		}
		else					//system info data, 32byte
		{
			for (i=0; i<69; i++)
			{
				tx_hex ((unsigned char) (i2c_read (1)));
			}
		
			tx_hex ((unsigned char) (i2c_read (0)));
		}

		i2c_stop();
		status_reg = (1<<no_mode); //read only 1 time
		PIXCIR_tx232_string (terminal_line);
	}
	else
	{
		status_reg = (1<<no_mode); //read only 1 time
		PIXCIR_tx232_string (no_debug_mode);

	}

}

/////////////////////////////////////////////////////////////////////////////////////////////////
// read button rawdata //////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////////////////

void read_button_rawdata(void) 
{ 
	int i; 
	signed char *p = pos1.button;

	i2c_start (); 
	i2c_write (I2C_WRITE); 
	i2c_write (BUTTON_RAW_ADDR);  
	if(!repeated_start) 
	i2c_stop(); 

	i2c_start (); 
	i2c_write (I2C_READ);
	PIXCIR_tx232_string (message_button_rawdata);

	for (i=0; i<7; i++) 
	{
		pos1.button[i] = i2c_read (1); 
	}
		 
	pos1.button[7] = i2c_read (0);
	  
	for (i=0; i<7; i++) 
	{ 
		PIXCIR_tx232_int_base10_g ((((int) (*(p++)))<<1),0); 
		PIXCIR_tx232 (','); 
	} 
	 
	PIXCIR_tx232_int_base10_g ((((int) (*p))<<1),0); 
	i2c_stop(); 
		
	PIXCIR_tx232_string (terminal_line); 
	PIXCIR_tx232_string (terminal_home); 
} 

/////////////////////////////////////////////////////////////////////////////////////////////////
// read button flag  ////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////////////////

void read_button(void) 
{ 
	int i; 
	unsigned char k,n;  

	i2c_start (); 
	i2c_write (I2C_WRITE); 
	i2c_write (1);  
	if(!repeated_start) 
	i2c_stop(); 

	i2c_start (); 
	i2c_write (I2C_READ);
	k = (unsigned char)i2c_read (0); 
	PIXCIR_tx232_string (message_button); 

	for (i=0; i<8; i++) 
	{ 		
		n = (((k << i) & 0x80) >> 7) & 0x01;
		PIXCIR_tx232_int_base10_g ((int)n,0);
		if(i!=7) 
			PIXCIR_tx232 (','); 
	}   

	i2c_stop(); 
		
	PIXCIR_tx232_string (terminal_line); 
	PIXCIR_tx232_string (terminal_home); 
} 
/////////////////////////////////////////////////////////////////////////////////////////////////
// read bootloader content //////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////////////////
void read_boot_version(unsigned char rst_p)
{
	if(rst_p)
	{
		rst_pulse();
		_delay_ms(10);
	}
	i2c_start ();
	i2c_write (I2C_READ);
	bootloader[0] = i2c_read (1);
	bootloader[1] = i2c_read (1);
	bootloader[2] = i2c_read (1);
	bootloader[3] = i2c_read (0);
	i2c_stop ();
}

void print_boot_version(void)
{
	tx_hex((unsigned char)bootloader[0]);
	tx_hex((unsigned char)bootloader[1]);
	tx_hex((unsigned char)bootloader[2]);
	tx_hex((unsigned char)bootloader[3]);
	PIXCIR_tx232('\r');
	PIXCIR_tx232('\n');
}
/////////////////////////////////////////////////////////////////////////////////////////////////
// read the eeprom content //////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////////////////
void read_eeprom(void)
{
	unsigned int i;
	unsigned char num=0;
	
	I2C_SLAVE = 0x5D;				// read bootloader version
	I2C_READ = (I2C_SLAVE<<1)|1;

	read_boot_version(1);

	if(bootloader[3] == 0x47)
		num = 12;
	else if(bootloader[3] == 0x48) 
		num = 8;
	else
		PIXCIR_tx232_string (unexpected_error);	

	I2C_SLAVE = 0x5C;
	I2C_WRITE = I2C_SLAVE<<1;
	I2C_READ = (I2C_SLAVE<<1)|1;
	rst_pulse();
	_delay_ms(200);

	i2c_time_out_enable = 0;	// diable the I2C time-out as the whole EEPROM read operation will last for much longer than the time-out value

	//write the specop register and the start address of the eeprom.
	i2c_start ();
	i2c_write (I2C_WRITE);
	i2c_write (SPECOP);
	i2c_write (1);
	i2c_write (0);				// Low Byte
	i2c_write (0);				// High Byte
	if(!repeated_start)
		i2c_stop();

	//read the eeprom
	i2c_start ();
	i2c_write (I2C_READ);
	PIXCIR_tx232('\r');
	PIXCIR_tx232('\n');

	for (i=0; i<((num*1024)-1); i++)
	{
		if (!(i%16))
		{
			PIXCIR_tx232('\r');
			PIXCIR_tx232('\n');
			PIXCIR_tx232_int_base10 (i>>4);
			PIXCIR_tx232 (':');
			PIXCIR_tx232 (' ');
		}
		
		tx_hex ((unsigned char) (i2c_read (1)));
	}

	tx_hex ((unsigned char) (i2c_read (0)));
	PIXCIR_tx232('\r');
	PIXCIR_tx232('\n');
	i2c_stop();

	status_reg = (1<<no_mode); //read only 1 time
	i2c_time_out_enable = 1;
}

void read_offsets_in_eeprom(void)
{
	unsigned int i;
	unsigned char num=0;

	I2C_SLAVE = 0x5D;				// read bootloader version
	I2C_READ = (I2C_SLAVE<<1)|1;

	read_boot_version(1);
	if(bootloader[3] == 0x47)
		num = 6;
	else if(bootloader[3] == 0x48) 
		num = 3;
	else
		PIXCIR_tx232_string (unexpected_error);	

	I2C_SLAVE = 0x5C;
	I2C_WRITE = I2C_SLAVE<<1;
	I2C_READ = (I2C_SLAVE<<1)|1;

	rst_pulse();
	_delay_ms(200);

	i2c_time_out_enable = 0;	// diable the I2C time-out as the whole EEPROM read operation will last for much longer than the time-out value

	//write the specop register and the start address of the eeprom.
	i2c_start ();
	i2c_write (I2C_WRITE);
	i2c_write (SPECOP);
	i2c_write (1);
	i2c_write (0x00);			// offset from beginning of the EEPROM section (OFFSET section is from 1k to 7k)
	i2c_write (0x04);
	if(!repeated_start)
		i2c_stop();

	//read the eeprom
	i2c_start ();
	i2c_write (I2C_READ);
	PIXCIR_tx232('\r');
	PIXCIR_tx232('\n');
	
	for (i=0; i<((num*1024)-1); i++)
	{
		if ((!(i%16)) && i)
		{
			PIXCIR_tx232('\\');
			PIXCIR_tx232('\r');
			PIXCIR_tx232('\n');
		}
		
		PIXCIR_tx232('0');
		PIXCIR_tx232('x');
		tx_hex_comma ((unsigned char) (i2c_read (1)));
	}

	PIXCIR_tx232('0');
	PIXCIR_tx232('x');
	tx_hex ((unsigned char) (i2c_read (0)));
	PIXCIR_tx232('\r');
	PIXCIR_tx232('\n');
	i2c_stop();

	status_reg = (1<<no_mode); //read only 1 time
	i2c_time_out_enable = 1;
}
/////////////////////////////////////////////////////////////////////////////////////////////////
// read the crc content /////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////////////////

void read_crc(void)
{
	unsigned char temp[2];

	//go to the CRC register
	i2c_start ();
	i2c_write (I2C_WRITE);
	i2c_write (62);
	if(!repeated_start)
		i2c_stop();

	//read the crc
	i2c_start ();
	i2c_write (I2C_READ);
	PIXCIR_tx232_string (message_CRC);
	temp[1] = i2c_read (1);
	temp[0] = i2c_read (0);

	PIXCIR_tx232_string (message_hex);
	tx_hex (temp[0]);
	tx_hex (temp[1]);
	i2c_stop();

	PIXCIR_tx232_string (terminal_line);
	PIXCIR_tx232_string (terminal_home);

	status_reg = (1<<no_mode); //read only 1 time
}

/////////////////////////////////////////////////////////////////////////////////////////////////
// set user mode ////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////////////////
//user_mode_flag 	=0 INT mode
//					=1 INT width
//					=2 Power mode
//					=3 idle_freq
//					=4 auto_idle_delay
//					=5 water mode
void set_user_mode(void)
{
     //write register  
	 i2c_start ();
     i2c_write (I2C_WRITE);	 
	 switch(user_mode_flag)
	 {
	 	case 0: i2c_write (INT_MODE);break;
		case 1: i2c_write (INT_WIDTH);break;
		case 2: i2c_write (POWER_MODE);break;
		case 3: i2c_write (IDLE_FREQ);break;
		case 4: i2c_write (AUTO_IDLE_DELAY);break;
		case 5: i2c_write (WATER_MODE);break;
		default : PIXCIR_tx232_string (unexpected_error);break;
	 }
	 i2c_write (hex & 0xFF);
	 if(!repeated_start)
         i2c_stop();

     //read register
     i2c_start ();
     i2c_write (I2C_WRITE);
	 switch(user_mode_flag)
	 {
	 	case 0: i2c_write (INT_MODE);break;
		case 1: i2c_write (INT_WIDTH);break;
		case 2: i2c_write (POWER_MODE);break;
		case 3: i2c_write (IDLE_FREQ);break;
		case 4: i2c_write (AUTO_IDLE_DELAY);break;
		case 5: i2c_write (WATER_MODE);break;
		default : break;
	 }
     if(!repeated_start)
         i2c_stop();

	i2c_start ();
	i2c_write (I2C_READ);
	switch(user_mode_flag)
	{
	 	case 0: PIXCIR_tx232_string (message_INT_mode);break;
		case 1: PIXCIR_tx232_string (message_INT_width);break;
		case 2: PIXCIR_tx232_string (message_power_mode);break;
		case 3: PIXCIR_tx232_string (message_idle_freq); break;
		case 4: PIXCIR_tx232_string (message_auto_idle_delay);break;
		case 5: PIXCIR_tx232_string (message_water_mode);break;
		default : break;
	}
	
	tx_hex ((unsigned char) (i2c_read (0)));
	i2c_stop();

	PIXCIR_tx232_string (terminal_line);
	PIXCIR_tx232_string (terminal_home);

	status_reg = (1<<no_mode); //read only 1 time
}

/////////////////////////////////////////////////////////////////////////////////////////////////
// Water feature ////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////////////////

void read_water_flag(void)
{
  	i2c_start ();
	i2c_write (I2C_WRITE); 
    i2c_write (0);		
	if(!repeated_start)
		i2c_stop();
	i2c_start ();
	i2c_write (I2C_READ);

	PIXCIR_tx232_string (message_water_flag);
    tx_hex ((unsigned char) ((i2c_read (0)>>7)&0x01));

	i2c_stop();

	PIXCIR_tx232_string (terminal_line);
	PIXCIR_tx232_string (terminal_home);

	status_reg = (1<<no_mode); //read only 1 time
}
/////////////////////////////////////////////////////////////////////////////////////////////////
// get XN and YN electrodes /////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////////////////

void get_XN_YN (void)
{
	unsigned int RAW_CTRL_register_save = RAW_CTRL_register;
//	unsigned char i,temp;

	RAW_CTRL_register = (CHOOSE_1);
	write_raw_ctrl_reg();

	i2c_start ();
	i2c_write (I2C_WRITE);
	i2c_write (RAW_ADDR);
	if(!repeated_start)
		i2c_stop();
	i2c_start ();
	i2c_write (I2C_READ);
	
	if(nbr_res)
	{
		PIXCIR_tx232_string (message_nbx);
		tx_hex((unsigned char) i2c_read(1));	//display X electrode number
		PIXCIR_tx232_string (terminal_line);

		PIXCIR_tx232_string (message_nby);
		tx_hex((unsigned char) i2c_read(0));	//display Y electrode number
		PIXCIR_tx232_string (terminal_line);
/*
		for(i=0;i<7;i++)
			i2c_read(1);

		temp = i2c_read (1);
		tx_hex ((unsigned char) (i2c_read (1)));	//display X resolution
		tx_hex_comma ((unsigned char) temp);

		temp = i2c_read (1);
		tx_hex ((unsigned char) (i2c_read (0)));	//display Y resolution
		tx_hex_comma ((unsigned char) temp);
*/
		nbr_res = 0;
		status_reg = (1<<no_mode);
	}
	else
	{
		nb_XN = i2c_read(1);
		nb_YN = i2c_read(0);
	}
	i2c_stop();
	
	//recover RAW_CTRL_register
	RAW_CTRL_register = RAW_CTRL_register_save;
	write_raw_ctrl_reg();
}

/////////////////////////////////////////////////////////////////////////////////////////////////
// get_report_rate //////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////////////////

void get_report_rate (void)
{
	char INT_reg;
	int i,j;
	int raw_control;
	unsigned int t;
//	unsigned int report_time=0;
	unsigned int report_timer[20];
/*
	//read the touch finger number
	i2c_start (); 
	i2c_write (I2C_WRITE); 
	i2c_write (0);  
	if(!repeated_start) 
		i2c_stop(); 

	i2c_start (); 
	i2c_write (I2C_READ);

	PIXCIR_tx232_string (message_touch_finger_number); 
	PIXCIR_tx232_int_base10_g(i2c_read (0),0);	
	PIXCIR_tx232_string (terminal_line);
	i2c_stop();
*/

	//store the INT_mode_register
	i2c_start ();
	i2c_write (I2C_WRITE);
	i2c_write (INT_MODE);
	if(!repeated_start)
		i2c_stop();
	i2c_start ();
	i2c_write (I2C_READ);
	INT_reg = i2c_read(0);
	i2c_stop();

	//enable INT interrupt
	write_INT(0x08);
	raw_control = RAW_CTRL_register;
	RAW_CTRL_register &= ~NO_ALGO;
	write_raw_ctrl_reg();
	_delay_ms(200);

	for (i=0;i<20;i++)					//get 20 times touch report time
	{
		while(!(PINB & _BV(PB1)));		//attb line is low 
		while(PINB & _BV(PB1));			//attb line is high

		TCCR0B=0x02;					//start timer0, Ftime0 = Fcpu/8, time0 clk = 1us

		while(!(PINB & _BV(PB1)));		//attb line is low 
		while (PINB & _BV(PB1));		//attb line is high
	
		TCCR0B=0x00;					//stop timer0
		
		report_timer[i]= timer0_counter;
		timer0_counter = 0;
		PIXCIR_tx232('\r');
	}

	for(j=0;j<19;j++)					//sort 20 times value
		for(i=0;i<20-j;i++)
			if(report_timer[i]>report_timer[i+1])
			{
				t=report_timer[i];
				report_timer[i]=report_timer[i+1];
				report_timer[i+1]=t;
			}

//	for(i=8;i<13;i++)					//get middle 5 value to calculate mean
//	{
//		report_time+=report_timer[i];		
//	}
//	report_time=report_time/5;


	PIXCIR_tx232_string (message_report_rate);  
	PIXCIR_tx232_int_base10_g((12500/report_timer[9]),0);
	PIXCIR_tx232('H');
	PIXCIR_tx232('z');
	
	//recover the INT_mode_register and RAW_CTRL_register
	write_INT(INT_reg);  
	 
	RAW_CTRL_register = raw_control;
	write_raw_ctrl_reg();
	_delay_ms(200);
	 
	PIXCIR_tx232_string (terminal_line);
	PIXCIR_tx232_string (terminal_home);

}

/////////////////////////////////////////////////////////////////////////////////////////////////
// calibrate the touch panel in user mode ///////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////////////////

void user_calibrate (void)
{

	//write the specop register
	i2c_start ();
	i2c_write (I2C_WRITE);
	i2c_write (SPECOP);
	i2c_write (3);
	i2c_stop ();

	PIXCIR_tx232_int_base10_g (0,0);
	PIXCIR_tx232('s');
	PIXCIR_tx232_string (terminal_line);

}

/////////////////////////////////////////////////////////////////////////////////////////////////
// cancel the auto-calibration offsets //////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////////////////

void user_autocalibr_cancel (void)
{
	//write the specop register
	i2c_start ();
	i2c_write (I2C_WRITE);
	i2c_write (SPECOP);
	i2c_write (4);
	i2c_stop ();

	PIXCIR_tx232_string (cancel_autocal);
}

/////////////////////////////////////////////////////////////////////////////////////////////////
// read the slave message field /////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////////////////

void read_slave_version(void)
{
	int i;
	unsigned char *p = &pos1.version[0];  
	i2c_start();
	i2c_write (I2C_WRITE);
	i2c_write (SLAVE_VERSION);
	if(!repeated_start)
		i2c_stop();

	i2c_start();
	i2c_write (I2C_READ);
	PIXCIR_tx232_string (message_slave_version);

	if(ver_format)
	{										// display in ASCII string

		for (i=0; i<31; i++)
			*((unsigned char*) (&pos1.version[0])+i)  = i2c_read (1);  
		*((unsigned char*) (&pos1.version[0])+31) = i2c_read (0);  

		for (i=0; i<32; i++)
		{
			if(*((unsigned char*) (&pos1.version[0])+i) > 128)
				PIXCIR_tx232_string (message_ver_over);
			else
				PIXCIR_tx232 (*(p++));
		} 
	} 
	else
	{										// display in HEX format
		for (i=0; i<31; i++)
			tx_hex ((unsigned char) (i2c_read (1)));
		tx_hex ((unsigned char) (i2c_read (0)));
	}

	i2c_stop();
	PIXCIR_tx232_string (terminal_line);
	PIXCIR_tx232_string (terminal_home);

	status_reg = (1<<no_mode); //read only 1 time
}

/////////////////////////////////////////////////////////////////////////////////////////////////
// display the fingers strength /////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////////////////

void display_strength (void)
{
	i2c_start ();
	i2c_write (I2C_WRITE);
	i2c_write (SIGNAL_X);
	
	if(!repeated_start)
		i2c_stop();
	
	i2c_start ();
	i2c_write (I2C_READ);
	PIXCIR_tx232('X');
	PIXCIR_tx232_string (strength_str);
	PIXCIR_tx232_int_base10_g (i2c_read(1),3);
	PIXCIR_tx232(',');
	PIXCIR_tx232(' ');
	PIXCIR_tx232('Y');
	PIXCIR_tx232_string (strength_str);
	PIXCIR_tx232_int_base10_g (i2c_read(0),3);
	PIXCIR_tx232('\r');
	PIXCIR_tx232('\n');
	i2c_stop();
}
/////////////////////////////////////////////////////////////////////////////////////////////////
// read tune mode register //////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////////////////
void read_tune_ctrl_register(void)
{	
	i2c_start ();
	i2c_write (I2C_WRITE);
//	i2c_write (TUNE_MODE_CONFIG);
	i2c_write (TUNE_CTRL);
	if(!repeated_start)
		i2c_stop();
	i2c_start ();
	i2c_write (I2C_READ);
	PIXCIR_tx232_string (message_tune_mode);
	tx_hex((unsigned char) i2c_read(0));
	i2c_stop ();		

	PIXCIR_tx232_string (terminal_line);
	PIXCIR_tx232_string (terminal_home);

	status_reg = (1<<no_mode); //read only 1 time
}
/////////////////////////////////////////////////////////////////////////////////////////////////
// write tune mode register /////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////////////////
void write_tune_mode_reg()
{	
     //write the tune mode register  
	 i2c_start ();
     i2c_write (I2C_WRITE);
     i2c_write (TUNE_MODE_CONFIG);
	 i2c_write (tune_mode_register & 0xFF);
	 i2c_stop();	

	 status_reg = (1<<no_mode); //read only 1 time
}

/////////////////////////////////////////////////////////////////////////////////////////////////
// write tune mode register /////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////////////////
/*void read_tune_raw_data (void)
{
	int i;
	int j;
	
	// TUNING
	if(tune_mode_register == TUNING)
	{
	 	//Method 0 raw data || M0 threshold onefinger || M0 threshold multifinger || Zerocrossing ||M0 bending avg data
		//Bending thresold data || Bending strength || Bending M0 threshold max || water thr || water ratio
		if (((RAW_CTRL_register & (METHOD | CHOOSE_1 | CHOOSE_0))==(CHOOSE_0))&&
		   (((TUNE_CTRL_register & (RAWDATA_S0|RAWDATA_S1|RAWDATA_S2|RAWDATA_S3))== 0) 
			|| ((TUNE_CTRL_register & (RAWDATA_S0|RAWDATA_S1|RAWDATA_S2|RAWDATA_S3))== (RAWDATA_S0)) 
			|| ((TUNE_CTRL_register & (RAWDATA_S0|RAWDATA_S1|RAWDATA_S2|RAWDATA_S3))== (RAWDATA_S0|RAWDATA_S1)) 
			|| ((TUNE_CTRL_register & (RAWDATA_S0|RAWDATA_S1|RAWDATA_S2|RAWDATA_S3))== (RAWDATA_S1)) 
			|| ((TUNE_CTRL_register & (RAWDATA_S0|RAWDATA_S1|RAWDATA_S2|RAWDATA_S3))== (RAWDATA_S1|RAWDATA_S2))
			|| ((TUNE_CTRL_register & (RAWDATA_S0|RAWDATA_S1|RAWDATA_S2|RAWDATA_S3))== (RAWDATA_S3))
			|| ((TUNE_CTRL_register & (RAWDATA_S0|RAWDATA_S1|RAWDATA_S2|RAWDATA_S3))== (RAWDATA_S0|RAWDATA_S3))
			|| ((TUNE_CTRL_register & (RAWDATA_S0|RAWDATA_S1|RAWDATA_S2|RAWDATA_S3))== (RAWDATA_S1|RAWDATA_S3))
			|| ((TUNE_CTRL_register & (RAWDATA_S0|RAWDATA_S1|RAWDATA_S2|RAWDATA_S3))== (RAWDATA_S0|RAWDATA_S1|RAWDATA_S3))
			|| ((TUNE_CTRL_register & (RAWDATA_S0|RAWDATA_S1|RAWDATA_S2|RAWDATA_S3))== (RAWDATA_S2|RAWDATA_S3))))
		{
			int rx;
			unsigned char Slave_sync = 1; 	//bending data = 0, normal rawdata = 1, invalid = 2
 		
			//M0 bending avg data
			if(((RAW_CTRL_register & ( METHOD | CHOOSE_1 | CHOOSE_0))==(CHOOSE_0))&&((TUNE_CTRL_register & (RAWDATA_S0|RAWDATA_S1|RAWDATA_S2|RAWDATA_S3))== (RAWDATA_S1|RAWDATA_S2)))
			{			
	
				i2c_start ();
				i2c_write (I2C_WRITE);
				i2c_write (0x39);
				i2c_write (Master_sync);
				i2c_stop();

				i2c_start ();
				i2c_write (I2C_WRITE);
				i2c_write (0x28);
				if(!repeated_start)
					i2c_stop();
				i2c_start ();
				i2c_write (I2C_READ);
				Slave_sync = i2c_read(0);
				i2c_stop();

				if(Slave_sync == Master_sync)
					Master_sync ^= 0x01;
				else
					Slave_sync = 2;
			}

			if(Slave_sync != 2)			// slave is busy, invalid
			{
				i2c_start ();
				i2c_write (I2C_WRITE);
				i2c_write (RAW_ADDR);
				if(!repeated_start)
					i2c_stop();
				i2c_start ();
				i2c_write (I2C_READ);
	
				if(Slave_sync == 0)
					PIXCIR_tx232('U');
				else
					PIXCIR_tx232('X');

				for (i=0; i<(nb_XN-1); i++)
				{
					rx = i2c_read(1);
					rx = rx+(((unsigned int)i2c_read(1))<<8);
					PIXCIR_tx232_int_base10_g (rx,0);
					if(i != (nb_XN-2))
						PIXCIR_tx232 (',');	
				}

				PIXCIR_tx232_string (terminal_line);

				if(Slave_sync == 0)
					PIXCIR_tx232('V');
				else
					PIXCIR_tx232('Y');

				for (i=0; i<(nb_YN-2); i++)
				{
					rx = i2c_read(1);
					rx = rx+(((unsigned int)i2c_read(1))<<8);
					PIXCIR_tx232_int_base10_g (rx,0);
					PIXCIR_tx232 (',');	
				}

				rx = i2c_read(1);
				rx = rx+(((unsigned int)i2c_read(0))<<8);
				i2c_stop();
				PIXCIR_tx232_int_base10_g (rx,0);
				PIXCIR_tx232_string (terminal_line);
				PIXCIR_tx232_string (terminal_home);
			}
		}
		//Method 1 raster mode || M1 LiftXY multifinger || M1 noise qualification 
		else if (((RAW_CTRL_register & (M1_BAND | OFFSET_LOWPASS | METHOD | CHOOSE_1 | CHOOSE_0))==(M1_BAND | OFFSET_LOWPASS | METHOD | CHOOSE_0))&&
		   		(((TUNE_CTRL_register & (RAWDATA_S0|RAWDATA_S1|RAWDATA_S2|RAWDATA_S3))== (RAWDATA_S2)) 
				|| ((TUNE_CTRL_register & (RAWDATA_S0|RAWDATA_S1|RAWDATA_S2|RAWDATA_S3))== (RAWDATA_S0|RAWDATA_S2)) 
				|| ((TUNE_CTRL_register & (RAWDATA_S0|RAWDATA_S1|RAWDATA_S2|RAWDATA_S3))== (RAWDATA_S0|RAWDATA_S1|RAWDATA_S2))))
		{
			unsigned int ATTb_counter = 0;
									
			for (j=0; j<=nb_YN; j++)
			{
				int rx;	

				//write cross_Y value
				i2c_start ();
				i2c_write (I2C_WRITE);
				i2c_write (CROSS_Y_REG);
				i2c_write ((char)j);
				i2c_stop ();
			
				if (!raster_frozen)	// Synchronize on ATTb if not freezed after single shot
				{
					while (PINB & _BV(PB1)) //attb line is high
					{
						_delay_us(6);
						ATTb_counter++;

						if (ATTb_counter >= ATTB_counter_max)
						{
							PIXCIR_tx232_string (ATTb_locked);
							ATTb_counter=0;
							break;
						}
					}
					while (!(PINB & _BV(PB1))) //attb line is low
					{
						_delay_us(6);
						ATTb_counter++;

						if (ATTb_counter >= ATTB_counter_max)
						{
							PIXCIR_tx232_string (ATTb_locked);
							ATTb_counter=0;
							break;
						}
					}

					while (PINB & _BV(PB1)) //attb line is high
					{
						_delay_us(6);
						ATTb_counter++;

						if (ATTb_counter >= ATTB_counter_max)
						{
							PIXCIR_tx232_string (ATTb_locked);
							ATTb_counter=0;
							break;
						}
					}
					while (!(PINB & _BV(PB1))) //attb line is low
					{
						_delay_us(6);
						ATTb_counter++;

						if (ATTb_counter >= ATTB_counter_max)
						{
							PIXCIR_tx232_string (ATTb_locked);
							ATTb_counter=0;
							break;
						}
					}
					_delay_ms(4);
				}
			
				i2c_start ();
				i2c_write (I2C_WRITE);
				i2c_write (RAW_ADDR);
				if(!repeated_start) 
					i2c_stop();
				i2c_start ();
				i2c_write (I2C_READ);
			
				if (j == 0){PIXCIR_tx232('S');}
				else {PIXCIR_tx232('R');};

				for (i=0; i<nb_XN; i++)				
				{
					rx=i2c_read(1);
					rx = rx+(((unsigned int)i2c_read(1))<<8);
					PIXCIR_tx232_int_base10_g (rx,0);
					PIXCIR_tx232 (',');		
				}

				rx=i2c_read(1);
				rx = rx+(((unsigned int)i2c_read(0))<<8);
				i2c_stop();
				PIXCIR_tx232_int_base10_g (rx,0);
				PIXCIR_tx232 (',');	

				PIXCIR_tx232_string (terminal_line);
			}
		}
	}
	if(tune_mode_register == QUALIFY)	// QUALIFY
	{
		if(((RAW_CTRL_register&(METHOD | CHOOSE_1 | CHOOSE_0))==(CHOOSE_0))&&((TUNE_CTRL_register & (RAWDATA_S0|RAWDATA_S1|RAWDATA_S2|RAWDATA_S3))==0))
		{
			int rx;	
			unsigned char i;
			
			i2c_start ();
			i2c_write (I2C_WRITE);
			i2c_write (RAW_ADDR);
			if(!repeated_start) 
				i2c_stop();
			i2c_start ();
			i2c_write (I2C_READ);

			PIXCIR_tx232 ('Q');	
			PIXCIR_tx232 (':');	
			
			for(i=0;i<11;i++)
			{
				rx = i2c_read(1);
				rx = rx+(((unsigned int)i2c_read(1))<<8);
				PIXCIR_tx232_int_base10_g (rx,1);
				PIXCIR_tx232 (',');	
			}
			
			rx = i2c_read(1);
			rx = rx+(((unsigned int)i2c_read(0))<<8);
			PIXCIR_tx232_int_base10_g (rx,1);

			i2c_stop();

			PIXCIR_tx232_string (terminal_line); 
			PIXCIR_tx232_string (terminal_home);
		}
	}
}*/
/////////////////////////////////////////////////////////////////////////////////////////////////
// increase/decrease data in I2C table //////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////////////////
void modify_data(unsigned char step,unsigned char c) //c=1 increase; c=0 decrease
{
	unsigned int rx;
	i2c_start ();
	i2c_write (I2C_WRITE);
	i2c_write ((hex>>8)&0xFF);
	if(!repeated_start)
		i2c_stop();
	i2c_start ();
	i2c_write (I2C_READ);

	if(((hex>>8)&0xFF)>118 &&((hex>>8)&0xFF)<127)
	{
		if(c)
		{
			rx = i2c_read(1)&0xFF;
			rx = rx+(((unsigned int)i2c_read(0))<<8);		
			rx = rx + (step&0xFF);
		}
		else
		{
			rx = i2c_read(1)&0xFF;
			rx = rx+(((unsigned int)i2c_read(0))<<8);
			rx = rx - (step&0xFF);
		}
	}
	else
	{
		if(c)
			rx=i2c_read(0) + step;
		else
			rx=i2c_read(0) - step;
	}
	i2c_stop();

	i2c_start ();
	i2c_write (I2C_WRITE);
	i2c_write ((hex>>8)&0xFF);
	if(((hex>>8)&0xFF)>118 &&((hex>>8)&0xFF)<127)
	{
		i2c_write (rx & 0xFF);
		i2c_write ((rx>>8) & 0xFF);
	}
	else 
		i2c_write (rx & 0xFF);

	i2c_stop(); 

	PIXCIR_tx232_string (message_i2c_addr);
	tx_hex((unsigned char)(hex>>8)&0xFF);
	PIXCIR_tx232_string (terminal_line);
	PIXCIR_tx232_string (message_i2c_data);

	if(((hex>>8)&0xFF)>118 &&((hex>>8)&0xFF)<127)
	{
		tx_hex((unsigned char)(rx>>8)&0xFF);
		tx_hex((unsigned char)rx&0xFF);
	}
	else
		tx_hex((unsigned char)rx&0xFF);

	PIXCIR_tx232_string (terminal_line);
//	PIXCIR_tx232_string (terminal_home);

	status_reg = (1<<no_mode); //read only 1 time
}
/////////////////////////////////////////////////////////////////////////////////////////////////
// main program /////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////////////////

//int main (void) __attribute__((naked)); 

int main (void)
{
	
	//set interruptions before using i2c.
	asm("sei");

	if (first_run)
	{
		//Avoid "crazy mouse" when plug the FTDI usb into the PC.
		unsigned int wait_loop;
		for (wait_loop = 1000; wait_loop <1; wait_loop--)
		{
			_delay_ms(20);
			PIXCIR_tx232_int_base10(wait_loop);
			PIXCIR_tx232('\r');
			PIXCIR_tx232('\n');
			
		}

		//Initial values
		ATTb_en = 0; //trig on ATTb line disabled
		ATTb_line = 0; //if ATTb_en == 1, trig on ATTb low
		PORTD &= ~(1<<PD0); //RST is 0 (the slave is RST active high)
		first_run=0;
	}

	master_mode=0; //user mode = 0; i2c mode = 1; engineering mode = 2; tune mode = 3. This mode select the syntax of the keyboard command.

	unsigned char I2C_keys_mode=0; //no action in I2C mode.
	unsigned char user_keys_mode=0; //no action in user mode.
//	unsigned char tune_keys_mode=0; //no action in tune mode.
	unsigned char skip_action=0;

	hex = 0;
		
	uart_rx.cmd_idx  = 0;
	uart_rx.buf_idx  = 0;
	uart_rx.echo_idx = 0;
	RAW_CTRL_register = 0;
	tune_mode_register = 0;
	
	unsigned char pix_start = 0;
	unsigned char pix_error = 0;
	unsigned int pix_line = 0;
	unsigned int ATTb_counter=0;


//				+----------------- reserve_1
//				|+---------------- reserve_2
//				||+--------------- reserve_3
//				|||+-------------- reserve_4	
//				||||+------------- reserve_5
//				|||||+------------ reserve_6
//	    		||||||+----------- reserve_7
//				|||||||+---------- reserve_8
//	    		||||||||+--------- tune_debug_mode
//        		|||||||||+-------- report_rate_mode
//        		||||||||||+------- button_flag_mode
//        		|||||||||||+------ strength 
//        		||||||||||||+----- button_mode
//        		|||||||||||||+---- debug_mode
//       		||||||||||||||+--- normal_mode
//        		|||||||||||||||+-- no_mode
//        		||||||||||||||||
status_reg =  0b0000000000000001;


	while (1)
	{
		I2C_WRITE = I2C_SLAVE<<1;
		I2C_READ = (I2C_SLAVE<<1)|1;

		while (uart_rx.cmd_idx != uart_rx.buf_idx)
		{
			//PIXCIR_tx232(uart_rx.buffer[uart_rx.cmd_idx]); //echo
			
			//tune mode
			if (master_mode == 3)
			{
				switch (uart_rx.buffer[uart_rx.cmd_idx])
				{
					//user mode
					case '#':
						master_mode=0;
						PIXCIR_tx232_string (terminal_line);
						PIXCIR_tx232_string(user_mode);
						break;
					
					//i2c mode
					case '@':
						master_mode=1;
						PIXCIR_tx232_string (terminal_line);
						PIXCIR_tx232_string(i2c_mode);
						break;
					
					//engineering mode
					case '$':
						master_mode=2;
						PIXCIR_tx232_string (terminal_line);
						PIXCIR_tx232_string(engineering_mode);
						break;

					//tune mode
					case '%':
						master_mode=3;
						PIXCIR_tx232_string (terminal_line);
						PIXCIR_tx232_string(tune_mode);
						break;
					/*
					// numbers
					case '0':
					case '1':
					case '2':
					case '3':
					case '4':
					case '5':
					case '6':
					case '7':
					case '8':
					case '9':
						hex = (hex << 4) + uart_rx.buffer[uart_rx.cmd_idx]-'0';
						hex_counter++;
						//no action, dont increase hex_counter
						if (tune_keys_mode == 0){hex_counter=0;};
						//write tune mode register
						if ((tune_keys_mode == 1) && (hex_counter == 2)) {tune_mode_register = hex;write_tune_mode_reg(); tune_keys_mode=0;};
						//increase data
						if ((tune_keys_mode == 2) && (hex_counter == 4)) {modify_data((unsigned char)hex&0xFF,1);tune_keys_mode=0;};
						//decrease data
						if ((tune_keys_mode == 3) && (hex_counter == 4)) {modify_data((unsigned char)hex&0xFF,0);tune_keys_mode=0;};
						break;

					case 'A':
					case 'B':
					case 'C':
					case 'D':
					case 'E':
					case 'F':
						hex = (hex << 4) + uart_rx.buffer[uart_rx.cmd_idx]-'A'+10;
						hex_counter++;
						//no action, dont increase hex_counter
						if (tune_keys_mode == 0){hex_counter=0;};
						//write tune mode register
						if ((tune_keys_mode == 1) && (hex_counter == 2)) {tune_mode_register = hex;write_tune_mode_reg(); tune_keys_mode=0;};
						//increase data
						if ((tune_keys_mode == 2) && (hex_counter == 4)) {modify_data((unsigned char)hex&0xFF,1);tune_keys_mode=0;};
						//decrease data
						if ((tune_keys_mode == 3) && (hex_counter == 4)) {modify_data((unsigned char)hex&0xFF,0);tune_keys_mode=0;};
						break;

					//write tune mode register
					case 't':
						tune_keys_mode = 1;
						hex_counter = 0;
						status_reg = (1<<no_mode);
						break;

					//read tune mode register
					case 'T':
						status_reg = (1<<no_mode);
						read_tune_ctrl_register();
						break;
				
				    //read the status of the RAW_CTRL_register
					case 'R':
						PIXCIR_plot_raw_ctrl_register();
						status_reg = (1<<no_mode);
						break;

					//increase data, press i+char+char+char+char
					case 'i':
						tune_keys_mode=2;
						hex_counter = 0;
						break;
					
					//decrease data, press e+char+char+char+char
					case 'e':
						tune_keys_mode=3;
						hex_counter = 0;
						break;

					//calibrate
					case 'z':
						user_calibrate();
						break;

					//set scan X axis for M1
					case 'X':
						set_M1_X();
						break;

					//////////////////////////////////////////////////////////////////////////////////////////
					//Program the different mode /////////////////////////////////////////////////////////////
					//////////////////////////////////////////////////////////////////////////////////////////

					//Method 0 raw data
					case 'd':
						get_XN_YN();			//get the number of electrodes
					    
						tune_mode_register=0;	//config tune mode register
						tune_mode_register |= TUNING;
						write_tune_mode_reg();
					
						RAW_CTRL_register=0;	//config rawctrl register
						RAW_CTRL_register |= CHOOSE_0;
						disable_algo();

						TUNE_CTRL_register=0;	//config tunectrl register
						write_tune_ctrl_reg();
						///////////////
						status_reg = (1<<tune_debug_mode);
						break;

					//M0 threshold onefinger display
					case 'o':
						get_XN_YN();			//get the number of electrodes
					    
						tune_mode_register=0;	//config tune mode register
						tune_mode_register |= TUNING;
						write_tune_mode_reg();
					
						RAW_CTRL_register=0;	//config rawctrl register
						RAW_CTRL_register |= CHOOSE_0;
						RAW_CTRL_register |= RAWDATA_S00;
						disable_algo();

						TUNE_CTRL_register=0;	//config tunectrl register
						TUNE_CTRL_register |= RAWDATA_S0;
						write_tune_ctrl_reg();
						///////////////
						status_reg = (1<<tune_debug_mode);
						break;

					//zerocossing display
					case 'c':
						get_XN_YN();			//get the number of electrodes
					    
						tune_mode_register=0;	//config tune mode register
						tune_mode_register |= TUNING;
						write_tune_mode_reg();
					
						RAW_CTRL_register=0;	//config rawctrl register
						RAW_CTRL_register |= CHOOSE_0;
						RAW_CTRL_register |= RAWDATA_S11;
						disable_algo();

						TUNE_CTRL_register=0;	//config tunectrl register
						TUNE_CTRL_register |= RAWDATA_S1;
						write_tune_ctrl_reg();
						///////////////
						status_reg = (1<<tune_debug_mode);
						break;

					//M0 threshold multifinger display
					case 'm':
						get_XN_YN();			//get the number of electrodes
					    
						tune_mode_register=0;	//config tune mode register
						tune_mode_register |= TUNING;
						write_tune_mode_reg();
					
						RAW_CTRL_register=0;	//config rawctrl register
						RAW_CTRL_register |= CHOOSE_0;
						RAW_CTRL_register |= RAWDATA_S00;
						RAW_CTRL_register |= RAWDATA_S11;
						disable_algo();

						TUNE_CTRL_register=0;	//config tunectrl register
						TUNE_CTRL_register |= RAWDATA_S0;
						TUNE_CTRL_register |= RAWDATA_S1;
						write_tune_ctrl_reg();
						///////////////
						status_reg = (1<<tune_debug_mode);
						break;

					//Method 1 raster mode
					case 'a':
						get_XN_YN();			//get the number of electrodes
					    
						tune_mode_register=0;	//config tune mode register
						tune_mode_register |= TUNING;
						write_tune_mode_reg();
					
						RAW_CTRL_register=0;	//config rawctrl register
						RAW_CTRL_register |= CHOOSE_0;
						RAW_CTRL_register |= METHOD;
						RAW_CTRL_register |= OFFSET_LOWPASS;
						RAW_CTRL_register |= M1_BAND;
						RAW_CTRL_register |= RAWDATA_S22;
						disable_algo();

						TUNE_CTRL_register=0;	//config tunectrl register
						TUNE_CTRL_register |= RAWDATA_S2;
						write_tune_ctrl_reg();
						///////////////
						status_reg = (1<<tune_debug_mode);
						break;

					//M1 lift xy multifinger display
					case 'f':
						get_XN_YN();			//get the number of electrodes
					    
						tune_mode_register=0;	//config tune mode register
						tune_mode_register |= TUNING;
						write_tune_mode_reg();
					
						RAW_CTRL_register=0;	//config rawctrl register
						RAW_CTRL_register |= CHOOSE_0;
						RAW_CTRL_register |= METHOD;
						RAW_CTRL_register |= OFFSET_LOWPASS;
						RAW_CTRL_register |= M1_BAND;
						RAW_CTRL_register |= RAWDATA_S00;
						RAW_CTRL_register |= RAWDATA_S22;
						disable_algo();

						TUNE_CTRL_register=0;	//config tunectrl register
						TUNE_CTRL_register |= RAWDATA_S0;
						TUNE_CTRL_register |= RAWDATA_S2;
						write_tune_ctrl_reg();
						///////////////
						status_reg = (1<<tune_debug_mode);
						break;

					//bending avg data display
					case 'b':
						get_XN_YN();			//get the number of electrodes
					    
						tune_mode_register=0;	//config tune mode register
						tune_mode_register |= TUNING;
						write_tune_mode_reg();
					
						RAW_CTRL_register=0;	//config rawctrl register
						RAW_CTRL_register |= CHOOSE_0;
						RAW_CTRL_register |= RAWDATA_S11;
						RAW_CTRL_register |= RAWDATA_S22;
						disable_algo();

						TUNE_CTRL_register=0;	//config tunectrl register
						TUNE_CTRL_register |= RAWDATA_S1;
						TUNE_CTRL_register |= RAWDATA_S2;
						write_tune_ctrl_reg();
						///////////////
						status_reg = (1<<tune_debug_mode);
						break;

					//bending threshold data display
					case 'r':
						get_XN_YN();			//get the number of electrodes
					    
						tune_mode_register=0;	//config tune mode register
						tune_mode_register |= TUNING;
						write_tune_mode_reg();
					
						RAW_CTRL_register=0;	//config rawctrl register
						RAW_CTRL_register |= CHOOSE_0;
						RAW_CTRL_register |= RAWDATA_S00;
						RAW_CTRL_register |= RAWDATA_S11;
						RAW_CTRL_register |= RAWDATA_S22;
						disable_algo();

						TUNE_CTRL_register=0;	//config tunectrl register
						TUNE_CTRL_register |= RAWDATA_S3;
						write_tune_ctrl_reg();
						///////////////
						status_reg = (1<<tune_debug_mode);
						break;

					//bending srength data display
					case 's':
						get_XN_YN();			//get the number of electrodes
					    
						tune_mode_register=0;	//config tune mode register
						tune_mode_register |= TUNING;
						write_tune_mode_reg();
					
						RAW_CTRL_register=0;	//config rawctrl register
						RAW_CTRL_register |= CHOOSE_0;
						disable_algo();

						TUNE_CTRL_register=0;	//config tunectrl register
						TUNE_CTRL_register |= RAWDATA_S0;
						TUNE_CTRL_register |= RAWDATA_S3;
						write_tune_ctrl_reg();
						///////////////
						status_reg = (1<<tune_debug_mode);
						break;

					//bending M0 threshold max display
					case 'x':
						get_XN_YN();			//get the number of electrodes
					    
						tune_mode_register=0;	//config tune mode register
						tune_mode_register |= TUNING;
						write_tune_mode_reg();
					
						RAW_CTRL_register=0;	//config rawctrl register
						RAW_CTRL_register |= CHOOSE_0;
						disable_algo();

						TUNE_CTRL_register=0;	//config tunectrl register
						TUNE_CTRL_register |= RAWDATA_S1;
						TUNE_CTRL_register |= RAWDATA_S3;
						write_tune_ctrl_reg();
						///////////////
						status_reg = (1<<tune_debug_mode);
						break;

					//water ratio display
					case 'k':
						get_XN_YN();			//get the number of electrodes
					    
						tune_mode_register=0;	//config tune mode register
						tune_mode_register |= TUNING;
						write_tune_mode_reg();
					
						RAW_CTRL_register=0;	//config rawctrl register
						RAW_CTRL_register |= CHOOSE_0;
						disable_algo();

						TUNE_CTRL_register=0;	//config tunectrl register
						TUNE_CTRL_register |= RAWDATA_S0;
						TUNE_CTRL_register |= RAWDATA_S1;
						TUNE_CTRL_register |= RAWDATA_S3;
						write_tune_ctrl_reg();
						///////////////
						status_reg = (1<<tune_debug_mode);
						break;

					//water threshold display
					case 'h':
						get_XN_YN();			//get the number of electrodes
					    
						tune_mode_register=0;	//config tune mode register
						tune_mode_register |= TUNING;
						write_tune_mode_reg();
					
						RAW_CTRL_register=0;	//config rawctrl register
						RAW_CTRL_register |= CHOOSE_0;
						disable_algo();

						TUNE_CTRL_register=0;	//config tunectrl register
						TUNE_CTRL_register |= RAWDATA_S2;
						TUNE_CTRL_register |= RAWDATA_S3;
						write_tune_ctrl_reg();
						///////////////
						status_reg = (1<<tune_debug_mode);
						break;

					//M1 noise qualification tuning
					case 'n':
						get_XN_YN();			//get the number of electrodes
					    
						tune_mode_register=0;	//config tune mode register
						tune_mode_register |= TUNING;
						write_tune_mode_reg();
					
						RAW_CTRL_register=0;	//config rawctrl register
						RAW_CTRL_register |= CHOOSE_0;
						RAW_CTRL_register |= METHOD;
						RAW_CTRL_register |= OFFSET_LOWPASS;
						RAW_CTRL_register |= M1_BAND;
						RAW_CTRL_register |= RAWDATA_S00;
						RAW_CTRL_register |= RAWDATA_S11;
						RAW_CTRL_register |= RAWDATA_S22;
						disable_algo();

						TUNE_CTRL_register=0;	//config tunectrl register
						TUNE_CTRL_register |= RAWDATA_S0;
						TUNE_CTRL_register |= RAWDATA_S1;
						TUNE_CTRL_register |= RAWDATA_S2;
						write_tune_ctrl_reg();
						///////////////
						status_reg = (1<<tune_debug_mode);
						break;

					//M1 noise qualification display
					case 'N':
						get_XN_YN();			//get the number of electrodes
						tune_mode_register=0;	//config tune mode register
						tune_mode_register |= QUALIFY;
						write_tune_mode_reg();
					
						RAW_CTRL_register=0;	//config rawctrl register
						RAW_CTRL_register |= CHOOSE_0;
						disable_algo();

						TUNE_CTRL_register=0;	//config tunectrl register
						write_tune_ctrl_reg();
						///////////////
						status_reg = (1<<tune_debug_mode);
						break;

					//read button rawdata
					case 'u':
						tune_mode_register=0;	//config tune mode register
						tune_mode_register |= TUNING;
						write_tune_mode_reg();
					
						RAW_CTRL_register=0;	//config rawctrl register
						RAW_CTRL_register |= CHOOSE_0;
						disable_algo();

						TUNE_CTRL_register=0;	//config tunectrl register
						write_tune_ctrl_reg();
						status_reg = (1<<button_mode);
						break;

					//"ALGO" display
					case 'G':
						get_XN_YN();			//get the number of electrodes
						tune_mode_register=0;	//config tune mode register
						tune_mode_register |= ALGO;
						write_tune_mode_reg();
					
						RAW_CTRL_register=0;	//config rawctrl register
						write_raw_ctrl_reg();

						TUNE_CTRL_register=0;	//config tunectrl register
						write_tune_ctrl_reg();
						///////////////
						status_reg = (1<<normal_mode);
						break;
					*/
					default:
						PIXCIR_tx232_string (message_error);
						break;
				}
			}
			//engineering mode
			else if (master_mode == 2)
			{
				switch (uart_rx.buffer[uart_rx.cmd_idx])
				{
					//user mode
					case '#':
						master_mode=0;
						PIXCIR_tx232_string (terminal_line);
						PIXCIR_tx232_string(user_mode);
						break;
					
					//i2c mode
					case '@':
						master_mode=1;
						PIXCIR_tx232_string (terminal_line);
						PIXCIR_tx232_string(i2c_mode);
						break;
					
					//engineering mode
					case '$':
						master_mode=2;
						PIXCIR_tx232_string (terminal_line);
						PIXCIR_tx232_string(engineering_mode);
						break;

					//tune mode
					case '%':
						master_mode=3;
						PIXCIR_tx232_string (terminal_line);
						PIXCIR_tx232_string(tune_mode);
						break;
					
					//enter the key of the engineering
					default:
					    i2c_start ();
						i2c_write (I2C_WRITE); //write data from master 2 slave
					    i2c_write (ENGINEERING_MODE_REG);
						i2c_write (uart_rx.buffer[uart_rx.cmd_idx]);
						i2c_stop();
						break;
				}

			}

			//i2c mode
			else if (master_mode == 1)
			{
				switch (uart_rx.buffer[uart_rx.cmd_idx])   // New i2c generic syntax
				{
					//user mode
					case '#':
						master_mode=0;
						PIXCIR_tx232_string (terminal_line);
						PIXCIR_tx232_string (user_mode);
						break;
					
					//i2c mode
					case '@':
						master_mode=1;
						PIXCIR_tx232_string (terminal_line);
						PIXCIR_tx232_string(i2c_mode);
						break;
					
					//engineering mode
					case '$':
						master_mode=2;
						PIXCIR_tx232_string (terminal_line);
						PIXCIR_tx232_string(engineering_mode);
						break;
					
					//tune mode
					case '%':
						master_mode=3;
						PIXCIR_tx232_string (terminal_line);
						PIXCIR_tx232_string(tune_mode);
						break;

					// numbers
					case '0':
					case '1':
					case '2':
					case '3':
					case '4':
					case '5':
					case '6':
					case '7':
					case '8':
					case '9':
						hex = (hex << 4) + uart_rx.buffer[uart_rx.cmd_idx]-'0';
						hex_counter++;
						//no action, dont increase hex_counter
						if (I2C_keys_mode == 0){hex_counter=0;};
						// read mode
						if ((I2C_keys_mode == 1) && (hex_counter == 4)) {I2C_mode_read(); I2C_keys_mode=0;};
						//write mode
						if ((I2C_keys_mode == 2) && (!(hex_counter & 1))) 
						{
							if(turn_8b==0)
								i2c_write (hex & 0xFF);
							else
							{
								if(download_counter == 0)					//send download data to slave (i2c)
									i2c_write (download_counter & 0xFF);	
								else if((download_counter % 7) == 0)				
								{
									i2c_stop ();
									_delay_ms(2);
									i2c_start();
									i2c_write (I2C_WRITE);
									i2c_write (download_counter & 0xFF);
								}
		
								i2c_write (hex & 0xFF);
								download_counter++;

								if(download_counter == 143)
								{
									i2c_write(0x00);
									i2c_write(0x00);
									i2c_write(0x00);
									i2c_write(0x00);
								}
							/*	if((download_counter % 7) == 0)				//send download data to GUI (uart) for testinng	
								{
									PIXCIR_tx232_string (terminal_line);
									tx_hex(download_counter & 0xFF);
									PIXCIR_tx232(' ');
									PIXCIR_tx232(' ');
									PIXCIR_tx232(' ');
								}
		
								tx_hex(hex & 0xFF);
								PIXCIR_tx232(' ');
								download_counter++;

								if(download_counter == 143)
								{
									tx_hex(0x00);
									PIXCIR_tx232(' ');
									tx_hex(0x00);
									PIXCIR_tx232(' ');
									tx_hex(0x00);
									PIXCIR_tx232(' ');
									tx_hex(0x00);
									PIXCIR_tx232(' ');
									PIXCIR_tx232_string (terminal_line);
								}*/
							}
						}
						//write the address of the slave
						if ((I2C_keys_mode == 3) && (hex_counter == 2)) {I2C_SLAVE=hex;hex=0; I2C_keys_mode=0;};
						//write the time out of the i2c
						if ((I2C_keys_mode == 4) && (hex_counter == 2)) {i2c_time_out_period=hex;hex=0; I2C_keys_mode=0;};
						break;

					case 'A':
					case 'B':
					case 'C':
					case 'D':
					case 'E':
					case 'F':
						hex = (hex << 4) + uart_rx.buffer[uart_rx.cmd_idx]-'A'+10;
						hex_counter++;
						// no action, dont increase hex_counter
						if (I2C_keys_mode == 0){hex_counter=0;};
						// read mode
						if ((I2C_keys_mode == 1) && (hex_counter == 4)) {I2C_mode_read(); I2C_keys_mode=0;};
						// write mode
						if ((I2C_keys_mode == 2) && (!(hex_counter & 1)))
						{
							if(turn_8b==0)
								i2c_write (hex & 0xFF);
							else
							{
								if(download_counter == 0)					//send download data to slave (i2c)
									i2c_write (download_counter & 0xFF);	
								else if((download_counter % 7) == 0)				
								{
									i2c_stop ();
									_delay_ms(2);
									i2c_start();
									i2c_write (I2C_WRITE);
									i2c_write (download_counter & 0xFF);
								}
		
								i2c_write (hex & 0xFF);
								download_counter++;

								if(download_counter == 143)
								{
									i2c_write(0x00);
									i2c_write(0x00);
									i2c_write(0x00);
									i2c_write(0x00);
								}
							
							/*	if((download_counter % 7) == 0)				//send download data to GUI (uart) for testinng	
								{
									PIXCIR_tx232_string (terminal_line);
									tx_hex(download_counter & 0xFF);
									PIXCIR_tx232(' ');
									PIXCIR_tx232(' ');
									PIXCIR_tx232(' ');
								}
		
								tx_hex(hex & 0xFF);
								PIXCIR_tx232(' ');
								download_counter++;

								if(download_counter == 143)
								{
									tx_hex(0x00);
									PIXCIR_tx232(' ');
									tx_hex(0x00);
									PIXCIR_tx232(' ');
									tx_hex(0x00);
									PIXCIR_tx232(' ');
									tx_hex(0x00);
									PIXCIR_tx232(' ');
									PIXCIR_tx232_string (terminal_line);
								}*/
							}
						}
						// write the address of the slave
						if ((I2C_keys_mode == 3) && (hex_counter == 2)) {I2C_SLAVE=hex;hex=0; I2C_keys_mode=0;};
						// write the time out of the i2c
						if ((I2C_keys_mode == 4) && (hex_counter == 2)) {i2c_time_out_period=hex;hex=0; I2C_keys_mode=0;};
						break;

					//read 4 char, press r+char+char+char+char
					case 'r':
						I2C_keys_mode=1;
						hex_counter = 0;
						break;
					
					//write 2 char, press w+char+char+s
					case 'w':
						i2c_time_out_enable = 0;
					/*	if(turn_8b==0)								//send download data to GUI (uart) for testinng
						{ 
							i2c_start ();
							i2c_write (I2C_WRITE);
						}
					*/
						i2c_start ();
						i2c_write (I2C_WRITE);
						I2C_keys_mode=2;
						hex_counter = 0;
						download_counter = 0;
						break;

					//Download in 143Bytes way
					case 'h':
						turn_8b = 0;
						break;
						
					//Download in 8Bytes way
					case 'H':
						turn_8b = 1;
						break;

					//write the address of the slave, press m+char+char
					case 'm':
						I2C_keys_mode=3;
						hex_counter = 0;
						break;
					
					//send 1 shot of coordinates positions
					case 'n':
						send_position();
						break;
					
					//stop bit
					case 's':
						i2c_stop ();
						i2c_time_out_enable = 1;
						I2C_keys_mode = 0;
						hex_counter   = 0;
						
						if((I2C_SLAVE==0x5D)&&(attb_pulse))
						{
							ATTb_counter=0;
							while (!(PINB & _BV(PB1)))	//attb line is low
							{
								ATTb_counter++;
								if(ATTb_counter>=ATTB_counter_max)
								break;
							}	

							ATTb_counter=0;
							while (PINB & _BV(PB1))		//attb line is high
							{
								ATTb_counter++;
								if(ATTb_counter>=ATTB_counter_max)
								break;
							}	
							attb_pulse = 0;
						}
						else if((I2C_SLAVE==0x5D)&&(attb_pulse==0))
						{	
							ATTb_counter=0;
							while (PINB & _BV(PB1))		//attb line is high
							{
								ATTb_counter++;
								if(ATTb_counter>=ATTB_counter_max)
								break;
							}	
							ATTb_counter=0;
							while (!(PINB & _BV(PB1)))	//attb line is low
							{
								ATTb_counter++;
								if(ATTb_counter>=ATTB_counter_max)
								break;
							}
						}
						
						if(pix_start)
						{	
							read_boot_version(0);
							if(pix_error == 0)
							{
								pix_error |= bootloader[2];
								pix_line++;
							}
							print_boot_version();
						}
						break;

					//stop bit for the last package of the pix file
					case 'l':
						i2c_stop ();
						i2c_time_out_enable = 1;
						I2C_keys_mode = 0;
						hex_counter   = 0;
						print_boot_version();
						break;

					//change attb pulse
					case 'o':
						attb_pulse = 1;
						break;
					
					//reset pulse
					case 'k':
						rst_pulse();
						break;
					
					//1 ms of delay
					case 'a':
						_delay_ms(2);
						break;

					//polarity of the reset pulse
					case 'p':
						rst_polarity();
						break;

					//send a sequence to enter in bootloader mode. Dont forget to change the address before.
					case 'b':
						PIXCIR_tx232_string (message_match_address);
						read_boot_version(1);
						print_boot_version();
						break;

					//read the status of the RAW_CTRL_register
					case 'R':
						status_reg = (1<<no_mode);
						PIXCIR_plot_raw_ctrl_register();
						break;

					//set the time out of the I2C
					case 'T':
						I2C_keys_mode=4;
						hex_counter = 0;
						break;
						
					//set repeated start
					case 'P':
						repeated_start=1;
						break;
							
					//unset repeated start
					case 'S':
						repeated_start=0;
						break;
						
					//enter master bootloader
					case 'G':
						enter_master_bootloader();
						break;					

					//download pix file start
					case 'L':
						pix_start = 1;
						break;					
						
					//download pix file result
					case 'Q':
						if(pix_error)
						{
							PIXCIR_tx232('F');
						}
						else
						{
							PIXCIR_tx232('S');
						}

						tx_hex ((unsigned char) ((pix_line-1)>>8) & 0xFF);
						tx_hex ((unsigned char) (pix_line-1) & 0xFF);
						tx_hex ((unsigned char) pix_error);
						PIXCIR_tx232('\r');
						I2C_SLAVE  = 0x5C;
						pix_line   = 0;
						pix_start  = 0;
						pix_error  = 0;
						break;	

					default:
						PIXCIR_tx232_string (message_error);
						break;
				}
			}
			
			//user mode
			else
			{	
				switch (uart_rx.buffer[uart_rx.cmd_idx])   // engineering SYNTAX
				{
					//user mode
					case '#':
						master_mode=0;
						PIXCIR_tx232_string (terminal_line);
						PIXCIR_tx232_string (user_mode);
						break;
					
					//i2c mode
					case '@':
						master_mode=1;
						PIXCIR_tx232_string (terminal_line);
						PIXCIR_tx232_string(i2c_mode);
						break;
					
					//engineering mode
					case '$':
						master_mode=2;
						PIXCIR_tx232_string (terminal_line);
						PIXCIR_tx232_string(engineering_mode);
						break;

					//tune mode
					case '%':
						master_mode=3;
						PIXCIR_tx232_string (terminal_line);
						PIXCIR_tx232_string(tune_mode);
						status_reg = (1<<no_mode);
						break;

					// addresses and numbers
					case '0':
					case '1':
					case '2':
					case '3':
					case '4':
					case '5':
					case '6':
					case '7':
					case '8':
					case '9':
						hex = (hex << 4) + uart_rx.buffer[uart_rx.cmd_idx]-'0';
						hex_counter++;
						//no action, dont increase hex_counter
						if (user_keys_mode == 0){hex_counter=0;};
						// set bit in RAW_CTRL_register
						if ((user_keys_mode == 1) && (hex_counter == 1)) {RAW_CTRL_set_bit(); user_keys_mode=0;};
						// unset bit in RAW_CTRL_register
						if ((user_keys_mode == 2) && (hex_counter == 1)) {RAW_CTRL_unset_bit(); user_keys_mode=0;};
						// set coordinate of cross_x and cross_y
						if ((user_keys_mode == 3) && (hex_counter == 4)) {set_crossX_crossY(); user_keys_mode=0;};
						// set INT mode/ INT width/power mode/idle freq/auto idle delay/water mode
						if ((user_keys_mode == 4) && (hex_counter == 2)) {set_user_mode(); user_keys_mode=0;};
						break;

					case 'A':
					case 'B':
					case 'C':
					case 'D':
					case 'E':
					case 'F':
						hex = (hex << 4) + uart_rx.buffer[uart_rx.cmd_idx]-'A'+10;
						hex_counter++;
						//no action, dont increase hex_counter
						if (user_keys_mode == 0){hex_counter=0;};
						// set bit in RAW_CTRL_register
						if ((user_keys_mode == 1) && (hex_counter == 1)) {RAW_CTRL_set_bit(); user_keys_mode=0;};
						// unset bit in RAW_CTRL_register
						if ((user_keys_mode == 2) && (hex_counter == 1)) {RAW_CTRL_unset_bit(); user_keys_mode=0;};
						// set coordinate of cross_x and cross_y
						if ((user_keys_mode == 3) && (hex_counter == 4)) {set_crossX_crossY(); user_keys_mode=0;};
						// set INT mode/ INT width/power mode/idle freq/auto idle delay/water mode
						if ((user_keys_mode >= 4) && (hex_counter == 2)) {set_user_mode(); user_keys_mode=0;};
						break;
					
					//////////////////////////////////////////////////////////////////////////////////////////
					//SET THE RAW CTRL REGISTER //////////////////////////////////////////////////////////////
					//////////////////////////////////////////////////////////////////////////////////////////

					//set bit in RAW_CTRL_register
					case 's':
						user_keys_mode=1;
						hex_counter = 0;
						break;
					
					//unset bit in RAW_CTRL_register					
					case 'u':
						user_keys_mode=2;
						hex_counter = 0;
						break;

					//disable freeze
					case 'U':
						disable_freeze();
						break;

					//enable offset_cancelation + low pass filter
					case 'o':
						calibrated();
						break;

					//disable offset_cancelation + low pass filter
					case 'O':
						not_calibrated();
						break;

					//enable offset_cancelation + low pass filter
					case 'j':
						set_sensitivity();
						break;

					//disable offset_cancelation + low pass filter
					case 'J':
						unset_sensitivity();
						break;

					//enable algorithm
					case 'g':
						enable_algo();
						break;

					//disable algorithm
					case 'G':
						disable_algo();
						break;

					//set scan X axis for M1
					case 'X':
						set_M1_X();
						break;

					//set scan Y axis for M1
					case 'x':
						set_M1_Y();
						break;

					//set small pattern
					case 't':
						set_pat_small();
						break;

					//set large pattern
					case 'T':
						set_pat_large();
						break;

					//enable drift comp 
					case 'y':
						enable_comp();
						break;

					//disable drift comp 
					case 'Y':
						disable_comp();
						break;

					//////////////////////////////////////////////////////////////////////////////////////////
					//Program the different mode /////////////////////////////////////////////////////////////
					//////////////////////////////////////////////////////////////////////////////////////////

					//normal mode
					case 'n':
						enable_algo ();
						RAW_CTRL_register=0;
						write_raw_ctrl_reg();
						status_reg = (1<<normal_mode);
						break;
					
					//quiet
					case 'q':
						status_reg = (1<<no_mode);
						break;

					//calibrate
					case 'z':
						user_calibrate();
						break;

					//display X & Y strength
					case 'N':
						enable_algo ();
						status_reg = (1<<strength);
						break;
					
					//run raw data
					case 'd':
						get_XN_YN(); //get the number of electrodes
						RAW_CTRL_register=0;
						RAW_CTRL_register |= CHOOSE_0;
						///////////////
						disable_algo();
						///////////////
						status_reg = (1<<debug_mode);
						break;

					//run raster mode
					case 'r':
						get_XN_YN(); //get the number of electrodes
						RAW_CTRL_register=0;
						RAW_CTRL_register |= CHOOSE_0;
						RAW_CTRL_register |= METHOD;
						RAW_CTRL_register |= M1_BAND;
						///////////////
						disable_algo();
						///////////////
						status_reg = (1<<debug_mode);
						break;

					//run system info
					case 'i':
						RAW_CTRL_register=0;
						RAW_CTRL_register |= CHOOSE_1;
						write_raw_ctrl_reg();
						status_reg = (1<<debug_mode);
						break;
					
					//single shot
					case 'S':						
						single_shot();
						break;

					//set cross X and cross Y coordinates
					case 'w':
						user_keys_mode=3;
						hex_counter = 0;
						break;

					//display 1 cross node in M1
					case 'c':
						RAW_CTRL_register=0;
						RAW_CTRL_register |= CHOOSE_0;
						RAW_CTRL_register |= METHOD;
						///////////////
						disable_algo();
						///////////////
						status_reg = (1<<debug_mode);
						break;

					//////////////////////////////////////////////////////////////////////////////////////////
					//button /////////////////////////////////////////////////////////////////////////////////
					//////////////////////////////////////////////////////////////////////////////////////////

					//read button rawdata
					case 'b':
						enable_algo ();
						RAW_CTRL_register=0;
						RAW_CTRL_register |= CHOOSE_0;
						write_raw_ctrl_reg();
						status_reg = (1<<button_mode);
						break;

					//read button flag
					case 'K':	
						RAW_CTRL_register=0;
						write_raw_ctrl_reg();					
						status_reg = (1<<button_flag_mode);
						break;

					//////////////////////////////////////////////////////////////////////////////////////////
					//Read eeprom ////////////////////////////////////////////////////////////////////////////
					//////////////////////////////////////////////////////////////////////////////////////////

					//read the eeprom
					case 'e':
						read_eeprom();
						break;

					//read offsets in the eeprom
					case '*':
						read_offsets_in_eeprom();
						break;

					//read eeprom stucture version
					case '&':
						RAW_CTRL_register=0;
						RAW_CTRL_register |= CHOOSE_1;
						write_raw_ctrl_reg();
						status_reg = (1<<debug_mode);
						EEPROM_version = 1;
						break;

					//cancel the auto-calibration offsets
					case '(':
						user_autocalibr_cancel();
						break;

					//read CRC checksum
					case 'm':
						read_crc();
						break;

					//read report rate
					case 'Q':
						 status_reg=(1<<report_rate_mode);
						 break;
						 
					//////////////////////////////////////////////////////////////////////////////////////////
					//INT/Power/Water mode ///////////////////////////////////////////////////////////////////
					//////////////////////////////////////////////////////////////////////////////////////////

					//set INT mode
					case 'M':
						user_keys_mode = 4;
						user_mode_flag = 0;
						hex_counter = 0;
						status_reg = (1<<no_mode);
						break;

					//read INT width
					case 'W':
					    user_keys_mode = 4;
						user_mode_flag = 1;
						hex_counter = 0;
						status_reg = (1<<no_mode);
						break;

					//read power mode
					case 'P':
					    user_keys_mode = 4;
						user_mode_flag = 2;
						hex_counter = 0;
						status_reg = (1<<no_mode);
						break;

					//set frequency of the scan in idle mode
					case 'f':
						user_keys_mode= 4;
						user_mode_flag = 3;
						hex_counter = 0;
						status_reg = (1<<no_mode);
						break;
						
					//set delay between the last touch and idle mode
					case 'I':
						user_keys_mode= 4;
						user_mode_flag = 4;
						hex_counter = 0;
						status_reg = (1<<no_mode);
						break;

					//dispaly the water flag of the Touching register 
					case ')':
						read_water_flag();
						break;

					//set water mode register
					case '^':
						user_keys_mode= 4;
						user_mode_flag = 5;
						hex_counter = 0;
						status_reg = (1<<no_mode);
						break;

					//////////////////////////////////////////////////////////////////////////////////////////
					//Program the hardware GPIO //////////////////////////////////////////////////////////////
					//////////////////////////////////////////////////////////////////////////////////////////

					//trig the when ATTb line is high
					case 'h':
						ATTb_line = 1;
						break;

					//trig the master when ATTb line is low
					case 'l':
						ATTb_line = 0;
						break;

					//enable trig on ATTb line
					case 'H':
						ATTb_en = 1;
						break;

					//disable trig on ATTb line
					case 'L':
						ATTb_en = 0;
						break;

					//short reset pulse (200 us)
					case 'k':
						rst_pulse();
						_delay_ms(100);
						break;

					//polarity of the reset pulse
					case 'p':
						rst_polarity();
						break;

					//////////////////////////////////////////////////////////////////////////////////////////
					//Informations ///////////////////////////////////////////////////////////////////////////
					//////////////////////////////////////////////////////////////////////////////////////////

					//version of the master firmware
					case 'v':
						PIXCIR_tx232_string (message_master_version);
					    if(pgm_read_byte ((unsigned char*) (0x3ffe)) == 0x5A)
    						PIXCIR_tx232_string (message_version);
						else
							PIXCIR_tx232_string (message_version_noboot);		
						PIXCIR_tx232_string (terminal_home);
						status_reg = (1<<no_mode);
						break;

					//version of the slave firmware  (ASCII format)
					case 'a':
						ver_format = 1;
						read_slave_version();
						break;

					//version of the slave firmware  (HEX format)
					case 'V':
						ver_format = 0;
						read_slave_version();
						break;

					//read the status of the RAW_CTRL_register
					case 'R':
						status_reg = (1<<no_mode);
						PIXCIR_plot_raw_ctrl_register();
						break;
					
					//read the number of x,y electrodes
					case 'Z':
						nbr_res =1;
						get_XN_YN();
						break;				 

					default:
						PIXCIR_tx232_string (message_error);
						break;
				}
			}
			uart_rx.cmd_idx = (uart_rx.cmd_idx + 1) % BUF_SIZE;
		}	
		
		//user mode and tune mode are treated
		if(master_mode==0||master_mode==3)
		{
			if (status_reg & (1<<no_mode)) //nop
			{
			}		
			else if (status_reg & (1<<normal_mode))
			{
				// Execute command according ATTb line
				if (ATTb_en && algo_enabled)
				{
					skip_action=0;
					while (((PINB & _BV(PB1))^(ATTb_line<<1))) // Wait untill ATTb line change
					{
						_delay_us(2);
						// chack if a character has been sent
						if (uart_rx.cmd_idx != uart_rx.buf_idx)
						{
							skip_action=1;
							break;
						}
					}
					
					if (!skip_action)
					{
						send_position();
					}
					
					while ((!((PINB & _BV(PB1))^(ATTb_line<<1)))&&(!skip_action)) // Wait untill ATTb line change again
					{
						_delay_us(2);

						// chack if a character has been sent
						if (uart_rx.cmd_idx != uart_rx.buf_idx)
						{
							skip_action=1;
							break;
						}
					}

					skip_action=0;
				}
				else
				{
					send_position();
				}

			}
			else if (status_reg & (1<<debug_mode))
			{
				read_raw_data();
			}
			else if (status_reg & (1<<button_mode))
			{
				read_button_rawdata();
			}
			else if (status_reg & (1<<button_flag_mode))
			{
				read_button();
			}
			else if (status_reg &(1<<report_rate_mode))
			{
				get_report_rate();
			}
			else if (status_reg & (1<<strength))
			{
				display_strength();
			}
			else if (status_reg & (1<<tune_debug_mode))
			{
			//	read_tune_raw_data();
			}
			else
			{
				PIXCIR_tx232_string (unexpected_error);
			}		
		}	
	}
}


